From d44532c6d3f4a72aad94843e6fee8c67fafbd7be Mon Sep 17 00:00:00 2001 From: Alexey Shakula Date: Thu, 18 May 2023 13:20:42 -0400 Subject: [PATCH] Merge v1.9.0 * commit '7887d32da60f54984a597abccbb0c883f3a51649': (82 commits) [RELEASE] Release version 1.9.0 (#2091) Use sdk_start_ts for MetricData start_ts for instruments having cumulative aggregation temporality. (#2086) [SEMANTIC CONVENTIONS] Upgrade to version 1.20.0 (#2088) [EXPORTER] Add OTLP HTTP SSL support (#1793) Make Windows build environment parallel (#2080) make some hints (#2078) Make some targets parallel in CI pipeline (#2076) [Metrics SDK] Implement Forceflush for Periodic Metric Reader (#2064) Upgraded semantic conventions to 1.19.0 (#2017) Bump actions/stale from 7 to 8 (#2070) Include directory path added for Zipkin exporter example (#2069) Ignore more warning of generated protobuf files than not included in `-Wall` and `-Wextra` (#2067) Add `ForceFlush` for all `LogRecordExporter`s and `SpanExporter`s. (#2000) Remove unused 'alerting' section from prometheus.yml in examples (#2055) Clean warnings in ETW exporters (#2063) Fix default value of `OPENTELEMETRY_INSTALL_default`. (#2062) [EXPORTER] GRPC endpoint scheme should take precedence over OTEL_EXPORTER_OTLP_TRACES_INSECURE (#2060) Fix view names in Prometheus example (#2034) Fix some docs typo (#2057) Checking indices before dereference (#2040) ... # Conflicts: # exporters/ostream/CMakeLists.txt # sdk/src/metrics/state/metric_collector.cc # sdk/src/metrics/state/temporal_metric_storage.cc --- .bazelrc | 3 + .clang-format | 3 + .cmake-format.py | 3 + .copyright-ignore | 52 + .github/workflows/ci.yml | 172 +- .github/workflows/dependencies_image.yml | 2 +- .github/workflows/stale.yml | 2 +- .gitignore | 28 + .gitmodules | 5 + CHANGELOG.md | 221 ++ CMakeLists.txt | 241 ++- DEPRECATED.md | 115 ++ INSTALL.md | 26 +- README.md | 12 +- WORKSPACE | 15 +- api/BUILD | 15 +- api/CHANGELOG.md | 26 - api/CMakeLists.txt | 73 +- api/include/opentelemetry/baggage/baggage.h | 2 +- .../opentelemetry/common/key_value_iterable.h | 27 + .../common/key_value_iterable_view.h | 56 + api/include/opentelemetry/common/macros.h | 34 +- .../opentelemetry/common/string_util.h | 4 +- .../context/propagation/global_propagator.h | 2 +- .../opentelemetry/context/runtime_context.h | 4 +- api/include/opentelemetry/logs/event_logger.h | 94 + .../logs/event_logger_provider.h | 36 + api/include/opentelemetry/logs/logger.h | 671 ++---- .../opentelemetry/logs/logger_provider.h | 52 +- .../opentelemetry/logs/logger_type_traits.h | 192 ++ api/include/opentelemetry/logs/noop.h | 47 +- api/include/opentelemetry/logs/provider.h | 31 +- api/include/opentelemetry/metrics/meter.h | 2 +- api/include/opentelemetry/nostd/detail/all.h | 3 + .../opentelemetry/nostd/detail/decay.h | 3 + .../nostd/detail/dependent_type.h | 3 + .../opentelemetry/nostd/detail/functional.h | 3 + .../opentelemetry/nostd/detail/invoke.h | 3 + .../opentelemetry/nostd/detail/trait.h | 3 + .../nostd/detail/type_pack_element.h | 3 + .../opentelemetry/nostd/detail/valueless.h | 3 + .../nostd/detail/variant_alternative.h | 3 + .../opentelemetry/nostd/detail/variant_fwd.h | 3 + .../opentelemetry/nostd/detail/variant_size.h | 3 + api/include/opentelemetry/nostd/detail/void.h | 3 + api/include/opentelemetry/nostd/shared_ptr.h | 2 - api/include/opentelemetry/trace/noop.h | 7 +- .../opentelemetry/trace/propagation/jaeger.h | 6 +- api/include/opentelemetry/trace/provider.h | 2 +- .../trace/semantic_conventions.h | 607 ++++-- api/include/opentelemetry/trace/span_id.h | 15 +- api/include/opentelemetry/trace/trace_state.h | 18 +- .../opentelemetry/trace/tracer_provider.h | 2 +- api/include/opentelemetry/version.h | 7 +- api/test/CMakeLists.txt | 3 + api/test/baggage/BUILD | 3 + api/test/baggage/CMakeLists.txt | 3 + api/test/baggage/propagation/BUILD | 3 + api/test/baggage/propagation/CMakeLists.txt | 3 + api/test/common/BUILD | 3 + api/test/common/CMakeLists.txt | 3 + api/test/context/BUILD | 3 + api/test/context/CMakeLists.txt | 3 + api/test/context/propagation/BUILD | 3 + api/test/context/propagation/CMakeLists.txt | 3 + api/test/core/BUILD | 18 + api/test/core/CMakeLists.txt | 11 + api/test/core/version_test.cc | 16 + api/test/logs/BUILD | 3 + api/test/logs/CMakeLists.txt | 3 + api/test/logs/logger_test.cc | 118 +- api/test/logs/provider_test.cc | 72 +- api/test/metrics/BUILD | 3 + api/test/metrics/CMakeLists.txt | 3 + api/test/nostd/BUILD | 3 + api/test/nostd/CMakeLists.txt | 3 + api/test/nostd/span_test.cc | 4 +- api/test/plugin/BUILD | 3 + api/test/plugin/CMakeLists.txt | 3 + api/test/trace/BUILD | 3 + api/test/trace/CMakeLists.txt | 3 + api/test/trace/propagation/BUILD | 3 + api/test/trace/propagation/CMakeLists.txt | 19 +- bazel/BUILD | 3 + bazel/curl.BUILD | 3 + bazel/curl.bzl | 15 +- bazel/nlohmann_json.BUILD | 3 + bazel/opentelemetry_proto.BUILD | 15 +- bazel/otel_cc_benchmark.bzl | 3 + bazel/repository.bzl | 20 +- buildscripts/pre-commit | 30 +- buildscripts/pre_release.sh | 2 +- buildscripts/semantic-convention/.gitignore | 1 - buildscripts/semantic-convention/generate.sh | 22 +- ci/Dockerfile | 3 + ci/do_ci.ps1 | 72 +- ci/do_ci.sh | 96 +- ci/docfx.cmd | 3 + ci/install_protobuf.sh | 36 +- ci/install_windows_bazelisk.ps1 | 3 + ci/install_windows_protobuf.ps1 | 3 + ci/ports/benchmark/portfile.cmake | 3 + ci/ports/protobuf/portfile.cmake | 3 + ci/setup_thrift.ps1 | 5 +- ci/setup_thrift.sh | 3 + ci/setup_windows_ci_environment.ps1 | 3 + ci/setup_windows_cmake.ps1 | 3 + cmake/ParseOsRelease.cmake | 5 +- cmake/modules/FindThrift.cmake | 3 + cmake/nlohmann-json.cmake | 121 +- cmake/opentelemetry-cpp-config.cmake.in | 13 +- cmake/opentelemetry-proto.cmake | 53 +- cmake/package.cmake | 4 +- cmake/proto-options-patch.cmake | 3 + docker/Dockerfile | 3 + docker/Dockerfile.alpine.base | 3 + docker/Dockerfile.centos | 3 + docker/Dockerfile.debian.deps | 3 + docker/grpc/CMakeLists.txt | 3 + docker/grpc/Dockerfile | 3 + docker/thrift/CMakeLists.txt | 3 + docker/thrift/Dockerfile | 3 + docker/ubuntuLatest/Dockerfile | 3 + docs/build-as-dll.md | 11 + docs/dependencies.md | 11 +- docs/deprecation-process.md | 433 ++++ docs/library-distribution.md | 2 +- docs/public/Makefile | 3 + docs/public/conf.py | 5 +- docs/testing-with-ssl.md | 351 ++++ docs/using-clang-format.md | 2 +- examples/CMakeLists.txt | 11 +- examples/batch/BUILD | 3 + examples/batch/CMakeLists.txt | 3 + examples/batch/main.cc | 14 +- examples/common/CMakeLists.txt | 3 + examples/common/foo_library/BUILD | 3 + examples/common/foo_library/CMakeLists.txt | 7 + examples/common/logs_foo_library/BUILD | 3 + .../common/logs_foo_library/CMakeLists.txt | 7 + .../common/logs_foo_library/foo_library.cc | 8 +- examples/common/metrics_foo_library/BUILD | 3 + .../common/metrics_foo_library/CMakeLists.txt | 3 + examples/etw_threads/CMakeLists.txt | 3 + examples/grpc/BUILD | 3 + examples/grpc/CMakeLists.txt | 3 + examples/grpc/README.md | 2 +- examples/grpc/client.cc | 6 +- examples/grpc/protos/messages.proto | 3 + examples/grpc/server.cc | 6 +- examples/grpc/tracer_common.h | 8 +- examples/http/BUILD | 3 + examples/http/CMakeLists.txt | 29 +- examples/http/README.md | 2 +- examples/http/client.cc | 7 +- examples/http/server.cc | 5 +- examples/http/tracer_common.h | 8 +- examples/jaeger/BUILD | 3 + examples/jaeger/CMakeLists.txt | 3 + examples/jaeger/main.cc | 9 +- examples/logs_simple/BUILD | 19 + examples/logs_simple/CMakeLists.txt | 22 + examples/logs_simple/README.md | 16 + examples/logs_simple/main.cc | 83 + examples/metrics_simple/BUILD | 3 + examples/metrics_simple/CMakeLists.txt | 3 + examples/metrics_simple/metrics_ostream.cc | 17 +- examples/multi_processor/BUILD | 3 + examples/multi_processor/CMakeLists.txt | 3 + examples/multi_processor/main.cc | 13 +- examples/multithreaded/BUILD | 3 + examples/multithreaded/CMakeLists.txt | 3 + examples/multithreaded/main.cc | 20 +- examples/otlp/BUILD | 3 + examples/otlp/CMakeLists.txt | 73 +- examples/otlp/README.md | 2 +- examples/otlp/grpc_log_main.cc | 35 + examples/otlp/grpc_main.cc | 21 +- examples/otlp/grpc_metric_main.cc | 13 +- examples/otlp/http_log_main.cc | 68 +- examples/otlp/http_main.cc | 21 +- .../config.dev.yaml | 3 + examples/plugin/CMakeLists.txt | 3 + examples/plugin/load/BUILD | 3 + examples/plugin/load/CMakeLists.txt | 3 + examples/plugin/plugin/BUILD | 3 + examples/plugin/plugin/CMakeLists.txt | 3 + examples/prometheus/BUILD | 3 + examples/prometheus/CMakeLists.txt | 3 + examples/prometheus/README.md | 42 +- examples/prometheus/main.cc | 34 +- examples/prometheus/prometheus.yml | 11 +- examples/prometheus/run.sh | 5 +- examples/simple/BUILD | 3 + examples/simple/CMakeLists.txt | 19 +- examples/simple/main.cc | 12 +- examples/zipkin/CMakeLists.txt | 3 + examples/zipkin/main.cc | 9 +- examples/zpages/BUILD | 15 +- exporters/CMakeLists.txt | 15 +- exporters/elasticsearch/BUILD | 3 + exporters/elasticsearch/CMakeLists.txt | 31 +- .../elasticsearch/es_log_record_exporter.h | 25 + .../src/es_log_record_exporter.cc | 71 +- exporters/etw/BUILD | 3 + exporters/etw/CMakeLists.txt | 57 +- .../opentelemetry/exporters/etw/etw_fields.h | 3 +- .../opentelemetry/exporters/etw/etw_logger.h | 80 +- .../exporters/etw/etw_tail_sampler.h | 2 + .../exporters/etw/etw_traceloggingdynamic.h | 3 + .../opentelemetry/exporters/etw/etw_tracer.h | 40 +- .../opentelemetry/exporters/etw/utils.h | 113 + exporters/etw/test/etw_logger_test.cc | 10 +- exporters/etw/test/etw_tracer_test.cc | 9 +- exporters/jaeger/BUILD | 4 + exporters/jaeger/CMakeLists.txt | 34 +- exporters/jaeger/README.md | 6 + .../exporters/jaeger/jaeger_exporter.h | 14 +- .../jaeger/jaeger_exporter_factory.h | 6 +- .../jaeger/jaeger_exporter_options.h | 8 +- exporters/jaeger/src/THttpTransport.cc | 2 +- exporters/jaeger/src/http_transport.h | 3 + exporters/jaeger/src/jaeger_exporter.cc | 5 + exporters/memory/BUILD | 3 + exporters/memory/CMakeLists.txt | 29 +- exporters/ostream/BUILD | 3 + exporters/ostream/CMakeLists.txt | 75 +- .../exporters/ostream/log_record_exporter.h | 8 + .../exporters/ostream/span_exporter.h | 8 + .../exporters/ostream/span_exporter_factory.h | 2 +- exporters/ostream/src/log_record_exporter.cc | 27 +- exporters/ostream/src/span_exporter.cc | 6 + exporters/ostream/test/ostream_log_test.cc | 185 +- exporters/ostream/test/ostream_metric_test.cc | 4 +- exporters/otlp/BUILD | 17 +- exporters/otlp/CMakeLists.txt | 32 +- .../exporters/otlp/otlp_environment.h | 376 +--- .../exporters/otlp/otlp_grpc_exporter.h | 8 + .../otlp/otlp_grpc_exporter_factory.h | 2 +- .../otlp/otlp_grpc_exporter_options.h | 2 +- .../otlp/otlp_grpc_log_record_exporter.h | 8 + .../otlp_grpc_log_record_exporter_factory.h | 2 +- .../otlp/otlp_grpc_metric_exporter_options.h | 2 +- .../exporters/otlp/otlp_http_client.h | 45 +- .../exporters/otlp/otlp_http_exporter.h | 8 + .../otlp/otlp_http_exporter_factory.h | 2 +- .../otlp/otlp_http_exporter_options.h | 27 +- .../otlp/otlp_http_log_record_exporter.h | 8 + .../otlp_http_log_record_exporter_factory.h | 2 +- .../otlp_http_log_record_exporter_options.h | 33 +- .../otlp/otlp_http_metric_exporter_options.h | 26 +- .../exporters/otlp/protobuf_include_prefix.h | 28 + exporters/otlp/src/otlp_environment.cc | 1006 +++++++++ exporters/otlp/src/otlp_grpc_exporter.cc | 7 + .../otlp/src/otlp_grpc_log_record_exporter.cc | 7 + exporters/otlp/src/otlp_http_client.cc | 53 +- exporters/otlp/src/otlp_http_exporter.cc | 20 + .../otlp/src/otlp_http_log_record_exporter.cc | 20 + .../otlp/src/otlp_http_metric_exporter.cc | 15 + exporters/otlp/src/otlp_metric_utils.cc | 14 +- exporters/otlp/src/otlp_recordable_utils.cc | 14 +- .../otlp/test/otlp_grpc_exporter_test.cc | 72 +- .../otlp_grpc_log_record_exporter_test.cc | 10 +- .../otlp/test/otlp_http_exporter_test.cc | 22 +- .../otlp_http_log_record_exporter_test.cc | 257 ++- .../test/otlp_http_metric_exporter_test.cc | 20 +- .../test/otlp_metrics_serialization_test.cc | 4 +- exporters/prometheus/BUILD | 17 +- exporters/prometheus/CMakeLists.txt | 40 +- .../exporters/prometheus/collector.h | 38 +- .../exporters/prometheus/exporter.h | 66 +- .../exporters/prometheus/exporter_utils.h | 6 +- exporters/prometheus/src/collector.cc | 64 +- exporters/prometheus/src/exporter.cc | 91 +- exporters/prometheus/src/exporter_utils.cc | 149 +- exporters/prometheus/test/CMakeLists.txt | 3 + exporters/prometheus/test/collector_test.cc | 368 +--- exporters/prometheus/test/exporter_test.cc | 137 +- .../prometheus/test/exporter_utils_test.cc | 53 +- exporters/zipkin/BUILD | 3 + exporters/zipkin/CMakeLists.txt | 47 +- .../exporters/zipkin/zipkin_exporter.h | 8 + .../zipkin/zipkin_exporter_options.h | 8 +- exporters/zipkin/src/zipkin_exporter.cc | 7 +- exporters/zipkin/test/zipkin_exporter_test.cc | 34 +- ext/BUILD | 3 + ext/CMakeLists.txt | 27 +- .../ext/http/client/curl/http_client_curl.h | 31 +- .../http/client/curl/http_operation_curl.h | 39 +- .../ext/http/client/http_client.h | 169 +- ext/src/CMakeLists.txt | 11 +- ext/src/dll/CMakeLists.txt | 55 + ext/src/dll/dllmain.cc | 20 + ext/src/dll/opentelemetry_cpp.src | 39 + ext/src/http/client/curl/BUILD | 3 + ext/src/http/client/curl/CMakeLists.txt | 42 +- ext/src/http/client/curl/http_client_curl.cc | 14 +- .../http/client/curl/http_operation_curl.cc | 643 +++++- ext/src/zpages/BUILD | 15 +- ext/src/zpages/CMakeLists.txt | 17 +- ext/test/CMakeLists.txt | 3 + ext/test/http/BUILD | 3 + ext/test/http/CMakeLists.txt | 11 +- ext/test/http/curl_http_test.cc | 32 +- ext/test/w3c_tracecontext_test/BUILD | 3 + ext/test/w3c_tracecontext_test/CMakeLists.txt | 25 +- ext/test/w3c_tracecontext_test/Dockerfile | 3 + ext/test/w3c_tracecontext_test/main.cc | 2 - ext/test/zpages/BUILD | 3 + ext/test/zpages/CMakeLists.txt | 3 + functional/CMakeLists.txt | 6 + functional/cert/ca_csr.json | 12 + functional/cert/ca_csr_b.json | 12 + functional/cert/client_csr.json | 12 + functional/cert/client_csr_b.json | 12 + functional/cert/garbage.pem | 1 + functional/cert/generate_cert.sh | 38 + functional/cert/server_csr.json | 12 + functional/cert/server_csr_b.json | 12 + functional/otlp/CMakeLists.txt | 10 + functional/otlp/Dockerfile | 7 + functional/otlp/func_http_main.cc | 1810 +++++++++++++++++ functional/otlp/otel-config-http.yaml | 32 + functional/otlp/otel-config-https.yaml | 39 + functional/otlp/otel-docker-config-http.yaml | 31 + functional/otlp/otel-docker-config-https.yaml | 38 + functional/otlp/run_test.sh | 127 ++ functional/otlp/run_test_mode.sh | 74 + opentracing-shim/BUILD | 106 + opentracing-shim/CMakeLists.txt | 63 + opentracing-shim/README.md | 53 + .../opentracingshim/propagation.h | 90 + .../opentracingshim/shim_utils.h | 165 ++ .../opentracingshim/span_context_shim.h | 66 + .../opentelemetry/opentracingshim/span_shim.h | 59 + .../opentracingshim/tracer_shim.h | 80 + opentracing-shim/src/shim_utils.cc | 89 + opentracing-shim/src/span_context_shim.cc | 46 + opentracing-shim/src/span_shim.cc | 164 ++ opentracing-shim/src/tracer_shim.cc | 162 ++ opentracing-shim/test/propagation_test.cc | 106 + opentracing-shim/test/shim_mocks.h | 230 +++ opentracing-shim/test/shim_utils_test.cc | 281 +++ .../test/span_context_shim_test.cc | 108 + opentracing-shim/test/span_shim_test.cc | 225 ++ opentracing-shim/test/tracer_shim_test.cc | 219 ++ sdk/BUILD | 3 + sdk/CHANGELOG.md | 27 - sdk/CMakeLists.txt | 51 +- .../sdk/common/attributemap_hash.h | 42 +- .../opentelemetry/sdk/common/env_variables.h | 51 +- .../instrumentation_scope.h | 86 +- .../sdk/logs/batch_log_record_processor.h | 2 + .../logs/batch_log_record_processor_factory.h | 2 +- .../opentelemetry/sdk/logs/event_logger.h | 52 + .../sdk/logs/event_logger_provider.h | 37 + .../sdk/logs/event_logger_provider_factory.h | 32 + sdk/include/opentelemetry/sdk/logs/exporter.h | 11 +- sdk/include/opentelemetry/sdk/logs/logger.h | 5 +- .../opentelemetry/sdk/logs/logger_provider.h | 26 +- .../sdk/logs/logger_provider_factory.h | 2 +- .../logs/multi_log_record_processor_factory.h | 2 +- .../simple_log_record_processor_factory.h | 2 +- .../metrics/aggregation/aggregation_config.h | 6 +- .../metrics/aggregation/default_aggregation.h | 3 +- .../aggregation/histogram_aggregation.h | 7 + .../sdk/metrics/data/point_data.h | 18 +- .../export/periodic_exporting_metric_reader.h | 8 +- .../metrics/instrument_metadata_validator.h | 4 +- .../opentelemetry/sdk/metrics/metric_reader.h | 9 +- .../sdk/metrics/state/async_metric_storage.h | 22 +- .../sdk/metrics/state/attributes_hashmap.h | 89 +- .../sdk/metrics/state/sync_metric_storage.h | 69 +- .../metrics/state/temporal_metric_storage.h | 3 + .../sdk/metrics/view/attributes_processor.h | 17 +- .../sdk/metrics/view/predicate.h | 8 +- .../opentelemetry/sdk/resource/resource.h | 6 +- .../sdk/resource/semantic_conventions.h | 100 +- .../sdk/trace/batch_span_processor.h | 2 + .../sdk/trace/batch_span_processor_factory.h | 2 +- .../opentelemetry/sdk/trace/exporter.h | 14 +- .../opentelemetry/sdk/trace/processor.h | 2 +- .../sdk/trace/simple_processor.h | 11 +- .../sdk/trace/simple_processor_factory.h | 2 +- .../opentelemetry/sdk/trace/tracer_context.h | 4 +- .../sdk/trace/tracer_context_factory.h | 2 +- .../sdk/trace/tracer_provider_factory.h | 2 +- .../opentelemetry/sdk/version/version.h | 24 +- sdk/src/CMakeLists.txt | 3 + sdk/src/common/BUILD | 27 +- sdk/src/common/CMakeLists.txt | 19 +- sdk/src/common/env_variables.cc | 196 ++ sdk/src/common/platform/BUILD | 15 +- sdk/src/logs/BUILD | 15 +- sdk/src/logs/CMakeLists.txt | 21 +- sdk/src/logs/batch_log_record_processor.cc | 44 +- sdk/src/logs/event_logger.cc | 56 + sdk/src/logs/event_logger_provider.cc | 41 + sdk/src/logs/event_logger_provider_factory.cc | 24 + sdk/src/logs/exporter.cc | 27 + sdk/src/logs/logger.cc | 49 +- sdk/src/logs/logger_provider.cc | 21 +- sdk/src/logs/simple_log_record_processor.cc | 6 +- sdk/src/metrics/BUILD | 15 +- sdk/src/metrics/CMakeLists.txt | 17 +- .../aggregation/histogram_aggregation.cc | 58 +- .../periodic_exporting_metric_reader.cc | 162 +- .../metrics/instrument_metadata_validator.cc | 10 +- sdk/src/metrics/meter.cc | 5 +- sdk/src/metrics/metric_reader.cc | 4 +- sdk/src/metrics/state/metric_collector.cc | 8 +- .../metrics/state/temporal_metric_storage.cc | 56 +- sdk/src/resource/BUILD | 16 +- sdk/src/resource/CMakeLists.txt | 17 +- sdk/src/resource/resource.cc | 5 +- sdk/src/resource/resource_detector.cc | 9 +- sdk/src/trace/BUILD | 15 +- sdk/src/trace/CMakeLists.txt | 18 +- sdk/src/trace/batch_span_processor.cc | 44 +- sdk/src/trace/exporter.cc | 23 + sdk/src/trace/samplers/trace_id_ratio.cc | 15 +- sdk/src/trace/tracer.cc | 14 +- sdk/src/trace/tracer_context.cc | 4 +- sdk/src/version/CMakeLists.txt | 17 +- sdk/src/version/version.cc | 27 +- sdk/test/CMakeLists.txt | 3 + sdk/test/common/BUILD | 15 + sdk/test/common/CMakeLists.txt | 6 +- sdk/test/common/attributemap_hash_test.cc | 1 + sdk/test/common/env_var_test.cc | 210 ++ sdk/test/instrumentationscope/BUILD | 3 + sdk/test/instrumentationscope/CMakeLists.txt | 3 + .../instrumentationscope_test.cc | 161 ++ sdk/test/logs/BUILD | 4 + sdk/test/logs/CMakeLists.txt | 8 +- .../logs/batch_log_record_processor_test.cc | 35 +- sdk/test/logs/logger_provider_sdk_test.cc | 55 +- sdk/test/logs/logger_sdk_test.cc | 158 +- .../logs/simple_log_record_processor_test.cc | 62 +- sdk/test/metrics/BUILD | 146 +- sdk/test/metrics/CMakeLists.txt | 27 +- sdk/test/metrics/aggregation_test.cc | 32 +- sdk/test/metrics/async_metric_storage_test.cc | 38 +- .../metrics/attributes_hashmap_benchmark.cc | 6 +- sdk/test/metrics/attributes_hashmap_test.cc | 34 +- sdk/test/metrics/common.cc | 68 + sdk/test/metrics/common.h | 60 + sdk/test/metrics/exemplar/BUILD | 3 + sdk/test/metrics/exemplar/CMakeLists.txt | 3 + .../histogram_aggregation_benchmark.cc | 78 + .../metrics/histogram_aggregation_test.cc | 115 ++ sdk/test/metrics/histogram_test.cc | 246 +++ sdk/test/metrics/measurements_benchmark.cc | 86 + sdk/test/metrics/meter_provider_sdk_test.cc | 47 +- sdk/test/metrics/meter_test.cc | 18 +- sdk/test/metrics/metric_reader_test.cc | 24 +- .../periodic_exporting_metric_reader_test.cc | 1 + sdk/test/metrics/sum_aggregation_benchmark.cc | 79 + sdk/test/metrics/sum_aggregation_test.cc | 163 ++ sdk/test/metrics/sync_instruments_test.cc | 44 +- .../sync_metric_storage_counter_test.cc | 27 +- .../sync_metric_storage_histogram_test.cc | 29 +- ...ync_metric_storage_up_down_counter_test.cc | 27 +- sdk/test/metrics/view_registry_test.cc | 12 +- sdk/test/resource/BUILD | 3 + sdk/test/resource/CMakeLists.txt | 3 + sdk/test/resource/resource_test.cc | 30 +- sdk/test/trace/BUILD | 3 + sdk/test/trace/CMakeLists.txt | 3 + sdk/test/trace/batch_span_processor_test.cc | 33 +- sdk/test/trace/simple_processor_test.cc | 73 +- sdk/test/trace/tracer_test.cc | 91 +- test_common/BUILD | 3 + test_common/CMakeLists.txt | 3 + .../http/client/nosend/http_client_nosend.h | 10 + test_common/src/CMakeLists.txt | 3 + test_common/src/http/client/nosend/BUILD | 3 + .../src/http/client/nosend/CMakeLists.txt | 3 + third_party/BUILD | 3 + third_party/opentracing-cpp | 1 + third_party_release | 5 +- tools/WORKSPACE | 3 + tools/build-bazel.cmd | 3 + tools/build-benchmark.cmd | 3 + tools/build-benchmark.sh | 3 + tools/build-clang-12.cmd | 3 + tools/build-clang.cmd | 3 + tools/build-docker.cmd | 3 + tools/build-gtest.sh | 3 + tools/build-nuget.cmd | 3 + tools/build-nuget.ps1 | 3 + tools/build-vcpkg.sh | 4 + tools/build-vs2015.cmd | 3 + tools/build-vs2017.cmd | 3 + tools/build-vs2019.cmd | 3 + tools/build-vs2022.cmd | 3 + tools/build.cmd | 3 + tools/build.sh | 4 + tools/check_copyright.sh | 97 + tools/download.cmd | 3 + tools/download.ps1 | 3 + tools/format.sh | 4 + tools/git-cl.cmd | 3 + tools/git-cl.sh | 4 + tools/install-vs-addons.cmd | 3 + tools/install.sh | 4 + tools/install_llvm-win32.ps1 | 3 + tools/install_llvm-win64.ps1 | 3 + tools/setup-buildtools-mac.sh | 4 + tools/setup-buildtools.cmd | 3 + tools/setup-buildtools.sh | 3 + tools/setup-cfssl.sh | 13 + tools/setup-cmake.sh | 4 + tools/setup-devenv.cmd | 3 + tools/setup-devenv.sh | 3 + tools/setup-ninja.sh | 4 + tools/setup-protobuf.sh | 4 + tools/vcvars.cmd | 3 + 518 files changed, 16326 insertions(+), 3802 deletions(-) create mode 100644 .copyright-ignore create mode 100644 DEPRECATED.md delete mode 100644 api/CHANGELOG.md create mode 100644 api/include/opentelemetry/logs/event_logger.h create mode 100644 api/include/opentelemetry/logs/event_logger_provider.h create mode 100644 api/include/opentelemetry/logs/logger_type_traits.h create mode 100644 api/test/core/version_test.cc delete mode 100644 buildscripts/semantic-convention/.gitignore create mode 100644 docs/build-as-dll.md create mode 100644 docs/deprecation-process.md create mode 100644 docs/testing-with-ssl.md create mode 100644 examples/logs_simple/BUILD create mode 100644 examples/logs_simple/CMakeLists.txt create mode 100644 examples/logs_simple/README.md create mode 100644 examples/logs_simple/main.cc create mode 100644 exporters/otlp/src/otlp_environment.cc create mode 100644 ext/src/dll/CMakeLists.txt create mode 100644 ext/src/dll/dllmain.cc create mode 100644 ext/src/dll/opentelemetry_cpp.src create mode 100644 functional/CMakeLists.txt create mode 100644 functional/cert/ca_csr.json create mode 100644 functional/cert/ca_csr_b.json create mode 100644 functional/cert/client_csr.json create mode 100644 functional/cert/client_csr_b.json create mode 100644 functional/cert/garbage.pem create mode 100755 functional/cert/generate_cert.sh create mode 100644 functional/cert/server_csr.json create mode 100644 functional/cert/server_csr_b.json create mode 100644 functional/otlp/CMakeLists.txt create mode 100644 functional/otlp/Dockerfile create mode 100644 functional/otlp/func_http_main.cc create mode 100644 functional/otlp/otel-config-http.yaml create mode 100644 functional/otlp/otel-config-https.yaml create mode 100644 functional/otlp/otel-docker-config-http.yaml create mode 100644 functional/otlp/otel-docker-config-https.yaml create mode 100755 functional/otlp/run_test.sh create mode 100755 functional/otlp/run_test_mode.sh create mode 100644 opentracing-shim/BUILD create mode 100644 opentracing-shim/CMakeLists.txt create mode 100644 opentracing-shim/README.md create mode 100644 opentracing-shim/include/opentelemetry/opentracingshim/propagation.h create mode 100644 opentracing-shim/include/opentelemetry/opentracingshim/shim_utils.h create mode 100644 opentracing-shim/include/opentelemetry/opentracingshim/span_context_shim.h create mode 100644 opentracing-shim/include/opentelemetry/opentracingshim/span_shim.h create mode 100644 opentracing-shim/include/opentelemetry/opentracingshim/tracer_shim.h create mode 100644 opentracing-shim/src/shim_utils.cc create mode 100644 opentracing-shim/src/span_context_shim.cc create mode 100644 opentracing-shim/src/span_shim.cc create mode 100644 opentracing-shim/src/tracer_shim.cc create mode 100644 opentracing-shim/test/propagation_test.cc create mode 100644 opentracing-shim/test/shim_mocks.h create mode 100644 opentracing-shim/test/shim_utils_test.cc create mode 100644 opentracing-shim/test/span_context_shim_test.cc create mode 100644 opentracing-shim/test/span_shim_test.cc create mode 100644 opentracing-shim/test/tracer_shim_test.cc delete mode 100644 sdk/CHANGELOG.md create mode 100644 sdk/include/opentelemetry/sdk/logs/event_logger.h create mode 100644 sdk/include/opentelemetry/sdk/logs/event_logger_provider.h create mode 100644 sdk/include/opentelemetry/sdk/logs/event_logger_provider_factory.h create mode 100644 sdk/src/common/env_variables.cc create mode 100644 sdk/src/logs/event_logger.cc create mode 100644 sdk/src/logs/event_logger_provider.cc create mode 100644 sdk/src/logs/event_logger_provider_factory.cc create mode 100644 sdk/src/logs/exporter.cc create mode 100644 sdk/src/trace/exporter.cc create mode 100644 sdk/test/common/env_var_test.cc create mode 100644 sdk/test/metrics/common.cc create mode 100644 sdk/test/metrics/common.h create mode 100644 sdk/test/metrics/histogram_aggregation_benchmark.cc create mode 100644 sdk/test/metrics/histogram_aggregation_test.cc create mode 100644 sdk/test/metrics/histogram_test.cc create mode 100644 sdk/test/metrics/measurements_benchmark.cc create mode 100644 sdk/test/metrics/sum_aggregation_benchmark.cc create mode 100644 sdk/test/metrics/sum_aggregation_test.cc create mode 160000 third_party/opentracing-cpp create mode 100755 tools/check_copyright.sh create mode 100755 tools/setup-cfssl.sh diff --git a/.bazelrc b/.bazelrc index 7127e8fc0a..4e87c7c9e0 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + # bazel configurations for running tests under sanitizers. # Based on https://github.com/bazelment/trunk/blob/master/tools/bazel.rc diff --git a/.clang-format b/.clang-format index 8d7c41ac90..2640295e65 100644 --- a/.clang-format +++ b/.clang-format @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + # See Clang docs: http://clang.llvm.org/docs/ClangFormatStyleOptions.html BasedOnStyle: Chromium diff --git a/.cmake-format.py b/.cmake-format.py index 1c2a64ae25..d232ac8ebb 100644 --- a/.cmake-format.py +++ b/.cmake-format.py @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + # If comment markup is enabled, don't reflow the first comment block in # eachlistfile. Use this to preserve formatting of your # copyright/licensestatements. diff --git a/.copyright-ignore b/.copyright-ignore new file mode 100644 index 0000000000..81c51bcd50 --- /dev/null +++ b/.copyright-ignore @@ -0,0 +1,52 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +# Ignore the following directories + +./.git/* +./.github/* +./third_party/benchmark/* +./third_party/boost/* +./third_party/googletest/* +./third_party/ms-gsl/* +./third_party/nlohmann-json/* +./third_party/opentelemetry-proto/* +./third_party/prometheus-cpp/* +./tools/vcpkg/* +./tools/ports/* + +# Third party code + +./api/include/opentelemetry/nostd/internal/absl/* +./exporters/jaeger/thrift-gen/* +./exporters/etw/include/opentelemetry/exporters/etw/TraceLoggingDynamic.h + +# Doc + +./docs/* + +## Ignore the following files patterns + +*.md +*.rst +*.png +*.log +*.patch +*.json +*.nuspec +*.pem + +# Packaging +*/CONTROL + +# LICENSE files +*/LICENSE + +# Ignore the following misc files + +./.bazelignore +./.bazelversion +./docker/.gitignore +.markdownlintignore +./ci/toc.yml +./ci/valgrind-suppressions diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7a692615fe..82e200fd35 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,8 +29,8 @@ jobs: sudo -E ./ci/setup_thrift.sh ./ci/do_ci.sh cmake.test - cmake_gcc_maintainer_test: - name: CMake gcc 12 (maintainer mode) + cmake_gcc_maintainer_sync_test: + name: CMake gcc 12 (maintainer mode, sync) runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -41,19 +41,64 @@ jobs: CC: /usr/bin/gcc-12 CXX: /usr/bin/g++-12 GOOGLETEST_VERSION: 1.12.1 + PROTOBUF_VERSION: 21.12 run: | sudo -E ./ci/setup_cmake.sh sudo -E ./ci/setup_ci_environment.sh - - name: run cmake gcc (maintainer mode) + sudo -E ./ci/install_protobuf.sh + - name: run cmake gcc (maintainer mode, sync) env: CC: /usr/bin/gcc-12 CXX: /usr/bin/g++-12 run: | sudo -E ./ci/setup_thrift.sh - ./ci/do_ci.sh cmake.maintainer.test + ./ci/do_ci.sh cmake.maintainer.sync.test + - name: generate test cert + env: + CFSSL_VERSION: 1.6.3 + run: | + sudo -E ./tools/setup-cfssl.sh + (cd ./functional/cert; ./generate_cert.sh) + - name: run func test + run: | + (cd ./functional/otlp; ./run_test.sh) + + cmake_gcc_maintainer_async_test: + name: CMake gcc 12 (maintainer mode, async) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: 'recursive' + - name: setup + env: + CC: /usr/bin/gcc-12 + CXX: /usr/bin/g++-12 + GOOGLETEST_VERSION: 1.12.1 + PROTOBUF_VERSION: 21.12 + run: | + sudo -E ./ci/setup_cmake.sh + sudo -E ./ci/setup_ci_environment.sh + sudo -E ./ci/install_protobuf.sh + - name: run cmake gcc (maintainer mode, async) + env: + CC: /usr/bin/gcc-12 + CXX: /usr/bin/g++-12 + run: | + sudo -E ./ci/setup_thrift.sh + ./ci/do_ci.sh cmake.maintainer.async.test + - name: generate test cert + env: + CFSSL_VERSION: 1.6.3 + run: | + sudo -E ./tools/setup-cfssl.sh + (cd ./functional/cert; ./generate_cert.sh) + - name: run func test + run: | + (cd ./functional/otlp; ./run_test.sh) - cmake_clang_maintainer_test: - name: CMake clang 14 (maintainer mode) + cmake_clang_maintainer_sync_test: + name: CMake clang 14 (maintainer mode, sync) runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -64,16 +109,61 @@ jobs: CC: /usr/bin/clang-14 CXX: /usr/bin/clang++-14 GOOGLETEST_VERSION: 1.12.1 + PROTOBUF_VERSION: 21.12 run: | sudo -E ./ci/setup_cmake.sh sudo -E ./ci/setup_ci_environment.sh - - name: run cmake clang (maintainer mode) + sudo -E ./ci/install_protobuf.sh + - name: run cmake clang (maintainer mode, sync) env: CC: /usr/bin/clang-14 CXX: /usr/bin/clang++-14 run: | sudo -E ./ci/setup_thrift.sh - ./ci/do_ci.sh cmake.maintainer.test + ./ci/do_ci.sh cmake.maintainer.sync.test + - name: generate test cert + env: + CFSSL_VERSION: 1.6.3 + run: | + sudo -E ./tools/setup-cfssl.sh + (cd ./functional/cert; ./generate_cert.sh) + - name: run func test + run: | + (cd ./functional/otlp; ./run_test.sh) + + cmake_clang_maintainer_async_test: + name: CMake clang 14 (maintainer mode, async) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: 'recursive' + - name: setup + env: + CC: /usr/bin/clang-14 + CXX: /usr/bin/clang++-14 + GOOGLETEST_VERSION: 1.12.1 + PROTOBUF_VERSION: 21.12 + run: | + sudo -E ./ci/setup_cmake.sh + sudo -E ./ci/setup_ci_environment.sh + sudo -E ./ci/install_protobuf.sh + - name: run cmake clang (maintainer mode, async) + env: + CC: /usr/bin/clang-14 + CXX: /usr/bin/clang++-14 + run: | + sudo -E ./ci/setup_thrift.sh + ./ci/do_ci.sh cmake.maintainer.async.test + - name: generate test cert + env: + CFSSL_VERSION: 1.6.3 + run: | + sudo -E ./tools/setup-cfssl.sh + (cd ./functional/cert; ./generate_cert.sh) + - name: run func test + run: | + (cd ./functional/otlp; ./run_test.sh) cmake_msvc_maintainer_test: name: CMake msvc (maintainer mode) @@ -127,13 +217,31 @@ jobs: sudo ./ci/install_abseil.sh ./ci/do_ci.sh cmake.abseil.test + cmake_opentracing_shim_test: + name: CMake test (with opentracing-shim) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: 'recursive' + - name: setup + run: | + sudo ./ci/setup_cmake.sh + sudo ./ci/setup_ci_environment.sh + - name: run cmake tests (enable opentracing-shim) + run: ./ci/do_ci.sh cmake.opentracing_shim.test + cmake_gcc_48_test: name: CMake gcc 4.8 (without otlp exporter) - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 with: submodules: 'recursive' + - name: Add Ubuntu Xenial package sources + run: | + sudo apt-add-repository 'deb http://archive.ubuntu.com/ubuntu/ xenial main' + sudo apt-add-repository 'deb http://archive.ubuntu.com/ubuntu/ xenial universe' - name: setup run: | sudo ./ci/setup_ci_environment.sh @@ -152,11 +260,15 @@ jobs: cmake_gcc_48_otlp_exporter_test: name: CMake gcc 4.8 (with otlp exporter) - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 with: submodules: 'recursive' + - name: Add Ubuntu Xenial package sources + run: | + sudo apt-add-repository 'deb http://archive.ubuntu.com/ubuntu/ xenial main' + sudo apt-add-repository 'deb http://archive.ubuntu.com/ubuntu/ xenial universe' - name: setup run: | sudo ./ci/setup_ci_environment.sh @@ -238,6 +350,22 @@ jobs: sudo ./ci/setup_grpc.sh ./ci/do_ci.sh cmake.exporter.otprotocol.test + cmake_do_not_install_test: + name: CMake do not install test (with otlp-exporter) + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3 + with: + submodules: 'recursive' + - name: setup + run: | + sudo ./ci/setup_cmake.sh + sudo ./ci/setup_ci_environment.sh + - name: run otlp exporter tests + run: | + sudo ./ci/setup_grpc.sh + ./ci/do_ci.sh cmake.do_not_install.test + plugin_test: name: Plugin -> CMake runs-on: ubuntu-latest @@ -489,6 +617,13 @@ jobs: - name: run tests run: ./ci/do_ci.sh format + copyright: + name: Copyright + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3 + - name: check copyright + run: ./tools/check_copyright.sh windows: name: CMake -> exporter proto @@ -507,6 +642,23 @@ jobs: - name: run otprotocol test run: ./ci/do_ci.ps1 cmake.exporter.otprotocol.test + windows-build-dll: + name: CMake -> exporter proto (Build as DLL) + runs-on: windows-2019 + steps: + - uses: actions/checkout@v3 + with: + submodules: 'recursive' + - name: setup + run: | + ./ci/setup_windows_cmake.ps1 + ./ci/setup_windows_ci_environment.ps1 + ./ci/install_windows_protobuf.ps1 + - name: run cmake test (DLL build) + run: ./ci/do_ci.ps1 cmake.dll.test + - name: run otprotocol test (DLL build) + run: ./ci/do_ci.ps1 cmake.exporter.otprotocol.dll.test + windows_with_async_export: name: CMake (With async export) -> exporter proto runs-on: windows-2019 diff --git a/.github/workflows/dependencies_image.yml b/.github/workflows/dependencies_image.yml index 2e3aa9bb42..d5a96bd432 100644 --- a/.github/workflows/dependencies_image.yml +++ b/.github/workflows/dependencies_image.yml @@ -21,7 +21,7 @@ jobs: uses: docker/setup-buildx-action@v2 - name: Build Image - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v4 with: builder: ${{ steps.buildx.outputs.name }} context: ci/ diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 5f49c9933d..534fb60743 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -7,7 +7,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v7 + - uses: actions/stale@v8 with: stale-issue-message: "This issue was marked as stale due to lack of activity." days-before-issue-stale: 60 diff --git a/.gitignore b/.gitignore index 87d2de3921..ce59c1a2e6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + # Ref. https://github.com/github/gitignore/blob/master/C%2B%2B.gitignore # Prerequisites *.d @@ -16,6 +19,7 @@ *.so *.dylib *.dll +*.pdb # Fortran module files *.mod @@ -51,3 +55,27 @@ tags .cache/clangd/* + +# Temporary dir used when generating semconv +./buildscripts/semantic-convention/opentelemetry-specification + +# Generated cert keys in functional tests +functional/cert/ca.csr +functional/cert/ca.pem +functional/cert/ca-key.pem +functional/cert/client_cert.csr +functional/cert/client_cert.pem +functional/cert/client_cert-key.pem +functional/cert/server_cert.csr +functional/cert/server_cert.pem +functional/cert/server_cert-key.pem +functional/cert/ca_b.csr +functional/cert/ca_b.pem +functional/cert/ca_b-key.pem +functional/cert/client_cert_b.csr +functional/cert/client_cert_b.pem +functional/cert/client_cert_b-key.pem +functional/cert/server_cert_b.csr +functional/cert/server_cert_b.pem +functional/cert/server_cert_b-key.pem +functional/cert/unreadable.pem diff --git a/.gitmodules b/.gitmodules index c422e39e27..88a78e5f94 100644 --- a/.gitmodules +++ b/.gitmodules @@ -32,3 +32,8 @@ branch = main path = third_party/nlohmann-json url = https://github.com/nlohmann/json branch = master + +[submodule "third_party/opentracing-cpp"] +path = third_party/opentracing-cpp +url = https://github.com/opentracing/opentracing-cpp.git +branch = master diff --git a/CHANGELOG.md b/CHANGELOG.md index 0efb6b1309..dd8051e359 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,178 @@ Increment the: ## [Unreleased] +Deprecations: + +* The Jaeger Exporter is deprecated, see [DEPRECATED](./DEPRECATED.md) for details. + +## [1.9.0] 2023-04-12 + +* [CI] Make build environment parallel (Windows) + [#2080](https://github.com/open-telemetry/opentelemetry-cpp/pull/2080) +* [CI] Make build environment parallel (Linux) + [#2076](https://github.com/open-telemetry/opentelemetry-cpp/pull/2076) +* [CI] Remove separate run of metrics ostream example + [#2030](https://github.com/open-telemetry/opentelemetry-cpp/pull/2030) + +* [BUILD] Include directory path added for Zipkin exporter example + [#2069](https://github.com/open-telemetry/opentelemetry-cpp/pull/2069) +* [BUILD] Ignore more warning in generated protobuf files + [#2067](https://github.com/open-telemetry/opentelemetry-cpp/pull/2067) +* [BUILD] Clean warnings in ETW exporters + [#2063](https://github.com/open-telemetry/opentelemetry-cpp/pull/2063) +* [BUILD] Fix default value of OPENTELEMETRY_INSTALL_default + [#2062](https://github.com/open-telemetry/opentelemetry-cpp/pull/2062) + +* [SEMANTIC CONVENTIONS] Upgrade to version 1.20.0 + [#2088](https://github.com/open-telemetry/opentelemetry-cpp/pull/2088) +* [SEMANTIC CONVENTIONS] Upgrade to version 1.19.0 + [#2017](https://github.com/open-telemetry/opentelemetry-cpp/pull/2017) + +* [API] Checking indices before dereference in string utils + [#2040](https://github.com/open-telemetry/opentelemetry-cpp/pull/2040) +* [API] Export factory class of log provider + [#2041](https://github.com/open-telemetry/opentelemetry-cpp/pull/2041) + +* [SDK] Implement Forceflush for Periodic Metric Reader + [#2064](https://github.com/open-telemetry/opentelemetry-cpp/pull/2064) +* [SDK] Add `ForceFlush` for all `LogRecordExporter` and `SpanExporter` + [#2000](https://github.com/open-telemetry/opentelemetry-cpp/pull/2000) +* [SDK] Fix schema URL precedence bug in `Resource::Merge` + [#2036](https://github.com/open-telemetry/opentelemetry-cpp/pull/2036) +* [SDK] Use sdk_start_ts for MetricData start_ts for instruments having + cumulative aggregation temporality. + [#2086](https://github.com/open-telemetry/opentelemetry-cpp/pull/2086) + +* [EXPORTER] Add OTLP HTTP SSL support + [#1793](https://github.com/open-telemetry/opentelemetry-cpp/pull/1793) +* [EXPORTER] GRPC endpoint scheme should take precedence over OTEL_EXPORTER_OTLP_TRACES_INSECURE + [#2060](https://github.com/open-telemetry/opentelemetry-cpp/pull/2060) + +* [EXAMPLES] Remove unused 'alerting' section from prometheus.yml in examples + [#2055](https://github.com/open-telemetry/opentelemetry-cpp/pull/2055) +* [EXAMPLES] Fix view names in Prometheus example + [#2034](https://github.com/open-telemetry/opentelemetry-cpp/pull/2034) + +* [DOC] Fix some docs typo + [#2057](https://github.com/open-telemetry/opentelemetry-cpp/pull/2057) +* [DOC] Update OpenTracing shim README.md + [#2028](https://github.com/open-telemetry/opentelemetry-cpp/pull/2028) +* [DOC] INSTALL doc clarifications + [#2078](https://github.com/open-telemetry/opentelemetry-cpp/pull/2078) + +Important changes: + +* [EXPORTER] GRPC endpoint scheme should take precedence over OTEL_EXPORTER_OTLP_TRACES_INSECURE + [#2060](https://github.com/open-telemetry/opentelemetry-cpp/pull/2060) + * The logic to decide whether or not an OTLP GRPC exporter uses SSL has + changed to comply with the specification: + * Before this change, the following settings were evaluated, in order: + * OTEL_EXPORTER_OTLP_TRACES_INSECURE (starting with 1.8.3) + * OTEL_EXPORTER_OTLP_INSECURE (starting with 1.8.3) + * OTEL_EXPORTER_OTLP_TRACES_SSL_ENABLE + * OTEL_EXPORTER_OTLP_SSL_ENABLE + * With this change, the following settings are evaluated, in order: + * The GRPC endpoint scheme, if provided: + * "https" imply with SSL, + * "http" imply without ssl. + * OTEL_EXPORTER_OTLP_TRACES_INSECURE + * OTEL_EXPORTER_OTLP_INSECURE + * OTEL_EXPORTER_OTLP_TRACES_SSL_ENABLE + * OTEL_EXPORTER_OTLP_SSL_ENABLE + * As a result, a behavior change for GRPC SSL is possible, + because the endpoint scheme now takes precedence. + Please verify configuration settings for the GRPC endpoint. +* [SDK] Add `ForceFlush` for all `LogRecordExporter` and `SpanExporter` + [#2000](https://github.com/open-telemetry/opentelemetry-cpp/pull/2000) + * `LogRecordExporter` and `SpanExporter` add a new virtual function + `ForceFlush`, and if users implement any customized `LogRecordExporter` and + `SpanExporter`, they should also implement this function. + There should be no impact if users only use factory to create exporters. + +Deprecations: + +* The Jaeger Exporter is deprecated, see [DEPRECATED](./DEPRECATED.md) for details. + +## [1.8.3] 2023-03-06 + +* Provide version major/minor/patch macros + [#2014](https://github.com/open-telemetry/opentelemetry-cpp/pull/2014) +* [BUILD] Add `OPENTELEMETRY_INSTALL` to allow user to skip install targets. + [#2022](https://github.com/open-telemetry/opentelemetry-cpp/pull/2022) +* [SDK] Rename the global SDK version variables to avoid naming clash + [#2011](https://github.com/open-telemetry/opentelemetry-cpp/pull/2011) +* [BUILD] Fix typo in CMakeLists.txt + [#2010](https://github.com/open-telemetry/opentelemetry-cpp/pull/2010) +* [EXPORTER] fix Prometheus test iterator iterator increment + [#2006](https://github.com/open-telemetry/opentelemetry-cpp/pull/2006) +* [SDK]Add attributes for InstrumentationScope + [#2004](https://github.com/open-telemetry/opentelemetry-cpp/pull/2004) +* [METRICS SDK] Performance improvement in measurement processing + [#1993](https://github.com/open-telemetry/opentelemetry-cpp/pull/1993) +* [EXAMPLE] Add example for logs ostream exporter + [#1992](https://github.com/open-telemetry/opentelemetry-cpp/pull/1992) +* [ETW Exporter] Support serialize span/log attributes into JSON + [#1991](https://github.com/open-telemetry/opentelemetry-cpp/pull/1991) +* [ETW Exporter]Do not overwrite ParentId when setting attribute on Span + [#1989](https://github.com/open-telemetry/opentelemetry-cpp/pull/1989) +* Upgrade prometheus-cpp to v1.1.0 + [#1954](https://github.com/open-telemetry/opentelemetry-cpp/pull/1954) +* Convert Prometheus Exporter to Pull MetricReader + [#1953](https://github.com/open-telemetry/opentelemetry-cpp/pull/1953) +* [DOCS] Add alpine packages to INSTALL.md + [#1957](https://github.com/open-telemetry/opentelemetry-cpp/pull/1957) +* [METRICS SDK] Add benchmark tests for Sum Aggregation. + [#1948](https://github.com/open-telemetry/opentelemetry-cpp/pull/1948) +* [BUILD] Build OpenTelemetry SDK and exporters into DLL + [#1932](https://github.com/open-telemetry/opentelemetry-cpp/pull/1932) +* [CI] Enforce copyright check in CI + [#1965](https://github.com/open-telemetry/opentelemetry-cpp/pull/1965) +* [BUILD] Fix typo GENENV -> GETENV + [#1972](https://github.com/open-telemetry/opentelemetry-cpp/pull/1972) +* [SEMANTIC CONVENTIONS] Upgrade to version 1.18.0 + [#1974](https://github.com/open-telemetry/opentelemetry-cpp/pull/1974) +* [EXT] Fix thread-safety when shutdown. + [#1977](https://github.com/open-telemetry/opentelemetry-cpp/pull/1977) +* [SDK] Fix missing ObservedTimestamp. + [#1985](https://github.com/open-telemetry/opentelemetry-cpp/pull/1985) +* [METRICS SDK] fix variable names + [#1987](https://github.com/open-telemetry/opentelemetry-cpp/pull/1987) +* [EXPORTER] Fix Prometheus server crash on listening to already used port + [#1986](https://github.com/open-telemetry/opentelemetry-cpp/pull/1986) +* [EXPORTER] Boolean environment variables not parsed per the spec + [#1982](https://github.com/open-telemetry/opentelemetry-cpp/pull/1982) +* [EXPORTER] Opentracing shim + [#1909](https://github.com/open-telemetry/opentelemetry-cpp/pull/1909) + +## [1.8.2] 2023-01-31 + +* Remove redundant macro check in nostd::shared_ptr [#1939](https://github.com/open-telemetry/opentelemetry-cpp/pull/1939) +* Fix typo in packages.cmake causing incorrect nuget package versions [#1936](https://github.com/open-telemetry/opentelemetry-cpp/pull/1936) +* [METRICS] Custom Aggregation support [#1899](https://github.com/open-telemetry/opentelemetry-cpp/pull/1899) +* Small fix in INSTALL.md for enabling building package. [#1930](https://github.com/open-telemetry/opentelemetry-cpp/pull/1930) +* [METRICS] Fix warning for misconfiguration of PeriodicExportingMetricReader [#1929](https://github.com/open-telemetry/opentelemetry-cpp/pull/1929) +* Make macros.h available for all source files via version.h [#1918](https://github.com/open-telemetry/opentelemetry-cpp/pull/1918) +* [METRICS] Histogram Aggregation: Fix bucket detection logic, + performance improvements, and benchmark tests [#1869](https://github.com/open-telemetry/opentelemetry-cpp/pull/1869) +* Remove unused namespace alias for nostd [#1914](https://github.com/open-telemetry/opentelemetry-cpp/pull/1914) +* [METRICS] Update meter.h [#1907](https://github.com/open-telemetry/opentelemetry-cpp/pull/1907) +* sdk::resource::Resource::Merge should be const [#1905](https://github.com/open-telemetry/opentelemetry-cpp/pull/1905) +* [METRICS] Collect and Export metric data before + PeriodicMetricReader shutdown. [#1860](https://github.com/open-telemetry/opentelemetry-cpp/pull/1860) +* [ETW EXPORTER] Add Virtual destructor for TailSampler, Update Maintainer + mode warnings for MSVC [#1897](https://github.com/open-telemetry/opentelemetry-cpp/pull/1897) +* Fix #1867 Orderly shutdown in examples [#1868](https://github.com/open-telemetry/opentelemetry-cpp/pull/1868) +* [METRICS] minor metrics handling optimizations [#1890](https://github.com/open-telemetry/opentelemetry-cpp/pull/1890) +* fix SpinLockMutex for Intel Compiler [#1885](https://github.com/open-telemetry/opentelemetry-cpp/pull/1885) +* [LOGS] Change BatchLogRecordProcessorFactory::Create to static method [#1876](https://github.com/open-telemetry/opentelemetry-cpp/pull/1876) +* Enable generating deb, rpm, NuGet, tgz, zip package through cmake build [#1662](https://github.com/open-telemetry/opentelemetry-cpp/pull/1662) +* Updated clone command in INSTALL.md [#1818](https://github.com/open-telemetry/opentelemetry-cpp/pull/1818) +* Small cleanup to remove old metrics design docs [#1855](https://github.com/open-telemetry/opentelemetry-cpp/pull/1855) +* [BUILD] Fix build error with older version of VS2017 compiler. [1857](https://github.com/open-telemetry/opentelemetry-cpp/pull/1857) +* [EXPORTERS] Enable setting Span endtime for ETW exporter [#1846](https://github.com/open-telemetry/opentelemetry-cpp/pull/1846) +* [REMOVAL] Remove deprecated experimental semantic conventions [#1743](https://github.com/open-telemetry/opentelemetry-cpp/pull/1743) +* [EXPORTERS] Fix console debug logs for otlp exporters. [#1848](https://github.com/open-telemetry/opentelemetry-cpp/pull/1848) +* [LOGS] Add `include_trace_context` and `EventLogger` [#1884](https://github.com/open-telemetry/opentelemetry-cpp/pull/1884) * [METRICS] Change BatchLogRecordProcessorFactory::Create to static method * [BUILD] Fix OTELCPP_MAINTAINER_MODE [#1844](https://github.com/open-telemetry/opentelemetry-cpp/pull/1844) * [BUILD] Fix compatibility when using clang and libc++, upgrade GTest and @@ -26,6 +198,55 @@ Increment the: [1871](https://github.com/open-telemetry/opentelemetry-cpp/pull/1871) * [BUILD] Migrate from @bazel_tools//platforms to [Bazel Platforms](https://github.com/bazelbuild/platforms) to enable Bazel 6.0.0 compatibility [#1873](https://github.com/open-telemetry/opentelemetry-cpp/pull/1873) +* [BUILD] Cleanup CMake makefiles for nlohmann_json + [#1912](https://github.com/open-telemetry/opentelemetry-cpp/pull/1912) +* [BUILD] Cleanup CMake makefiles for CURL usage + [#1916](https://github.com/open-telemetry/opentelemetry-cpp/pull/1916) +* [SEMANTIC CONVENTIONS] Upgrade to version 1.17.0 + [#1927](https://github.com/open-telemetry/opentelemetry-cpp/pull/1927) +* [MAINTAINER DOC] Define and document a deprecation process, + [DEPRECATION] Deprecate the Jaeger exporter, + implemented by [#1923](https://github.com/open-telemetry/opentelemetry-cpp/pull/1923) +* [BUILD] OTLP HTTP Exporter has build warnings in maintainer mode + [#1943](https://github.com/open-telemetry/opentelemetry-cpp/pull/1943) + +Deprecations: + +* [MAINTAINER DOC] Define and document a deprecation process, + [#1923](https://github.com/open-telemetry/opentelemetry-cpp/pull/1923) + * A new file, [DEPRECATED](./DEPRECATED.md) list all the code currently + deprecated. + * A new [deprecation process](./docs/deprecation-process.md) details the plan to + deprecate and later remove code. +* [DEPRECATION] Deprecate the Jaeger exporter + [#1923](https://github.com/open-telemetry/opentelemetry-cpp/pull/1923) + * The Jaeger Exporter is deprecated, see [DEPRECATED](./DEPRECATED.md) for details. + +Important changes: + +* [BUILD] Cleanup CMake makefiles for CURL usage + [#1916](https://github.com/open-telemetry/opentelemetry-cpp/pull/1916) + * CMake option `WITH_OTLP_HTTP` + * Before this change, the CMake option `WITH_OTLP_HTTP` was unpredictable, + sometime set to ON and sometime set to OFF by default, + depending on whether a CURL package was found or not. + The option `WITH_OTLP_HTTP` was sometime not displayed in the ccmake + UI, making it impossible to even discover there is an option of that name. + * With this change, CMake option `WITH_OTLP_HTTP` is always OFF by + default. WITH_OTLP_HTTP MUST be set to ON explicitly to build the + OTLP HTTP exporter. The option is always visible in the ccmake UI. + * CMake option `BUILD_W3CTRACECONTEXT_TEST` + * Before this change, the W3C trace context tests were built, or + not, in an unpredictable way, depending on the presence, or not, of a + CURL package. In particular, the build could ignore the W3C trace + context tests even when BUILD_W3CTRACECONTEXT_TEST=ON. + * With this change, option BUILD_W3CTRACECONTEXT_TEST is honored. + * HTTP client/server examples + * Before this change, the HTTP client/server examples were built, or + not, in an unpredictable way, depending on the presence, or not, of a + CURL package. + * With this change, a new option `WITH_EXAMPLES_HTTP` is used to + build the HTTP client/server examples. ## [1.8.1] 2022-12-04 diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b17b207ae..eef100f164 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + cmake_minimum_required(VERSION 3.1) # See https://cmake.org/cmake/help/v3.3/policy/CMP0057.html required by certain @@ -5,7 +8,7 @@ cmake_minimum_required(VERSION 3.1) cmake_policy(SET CMP0057 NEW) # See https://cmake.org/cmake/help/v3.12/policy/CMP0074.html required by certain -# version of zlib which is dependeded by cURL. +# version of zlib which CURL depends on. if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.12") cmake_policy(SET CMP0074 NEW) endif() @@ -107,12 +110,21 @@ else() ) endif() +option(WITH_NO_DEPRECATED_CODE "Do not include deprecated code" OFF) + option(WITH_STL "Whether to use Standard Library for C++ latest features" OFF) option(WITH_GSL "Whether to use Guidelines Support Library for C++ latest features" OFF) option(WITH_ABSEIL "Whether to use Abseil for C++latest features" OFF) +set(OPENTELEMETRY_INSTALL_default ON) +if(NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + set(OPENTELEMETRY_INSTALL_default OFF) +endif() +option(OPENTELEMETRY_INSTALL "Whether to install opentelemetry targets" + ${OPENTELEMETRY_INSTALL_default}) + if(NOT DEFINED CMAKE_CXX_STANDARD) if(WITH_STL) # Require at least C++17. C++20 is needed to avoid gsl::span @@ -148,6 +160,10 @@ if(WITH_STL) endif() option(WITH_OTLP "Whether to include the OpenTelemetry Protocol in the SDK" OFF) + +option(WITH_OTLP_HTTP "Whether to include the OTLP http exporter in the SDK" + OFF) + option(WITH_ZIPKIN "Whether to include the Zipkin exporter in the SDK" OFF) option(WITH_PROMETHEUS "Whether to include the Prometheus Client in the SDK" @@ -158,7 +174,7 @@ option(WITH_ELASTICSEARCH option(WITH_ZPAGES "Whether to include the Zpages Server in the SDK" OFF) -option(WITH_JAEGER "Whether to include the Jaeger exporter" OFF) +option(WITH_JAEGER "DEPRECATED - Whether to include the Jaeger exporter" OFF) option(WITH_NO_GETENV "Whether the platform supports environment variables" OFF) @@ -170,6 +186,8 @@ option(BUILD_W3CTRACECONTEXT_TEST "Whether to build w3c trace context" OFF) option(OTELCPP_MAINTAINER_MODE "Build in maintainer mode (-Wall -Werror)" OFF) +option(WITH_OPENTRACING "Whether to include the Opentracing shim" OFF) + set(OTELCPP_PROTO_PATH "" CACHE PATH "Path to opentelemetry-proto") @@ -195,11 +213,42 @@ option( OFF) option(WITH_EXAMPLES "Whether to build examples" ON) +# This requires CURL, OFF by default. +option( + WITH_EXAMPLES_HTTP + "Whether to build http client/server examples. Requires WITH_EXAMPLES and CURL" + OFF) + +option(WITH_FUNC_TESTS "Whether to build functional tests" ON) + option(WITH_LOGS_PREVIEW "Whether to build logs preview" OFF) -option(WITH_ASYNC_EXPORT_PREVIEW "Whether enable async export" OFF) +option(WITH_ASYNC_EXPORT_PREVIEW "Whether to enable async export" OFF) + +# EXPERIMENTAL +option(WITH_OTLP_HTTP_SSL_PREVIEW "Whether to enable otlp http ssl export" OFF) + +# EXPERIMENTAL +option(WITH_OTLP_HTTP_SSL_TLS_PREVIEW + "Whether to enable otlp http ssl tls min/max/cipher options" OFF) + # Exemplar specs status is experimental, so behind feature flag by default option(WITH_METRICS_EXEMPLAR_PREVIEW - "Whethere to enable exemplar within metrics" OFF) + "Whether to enable exemplar within metrics" OFF) + +# +# Verify options dependencies +# + +if(WITH_EXAMPLES_HTTP AND NOT WITH_EXAMPLES) + message(FATAL_ERROR "WITH_EXAMPLES_HTTP=ON requires WITH_EXAMPLES=ON") +endif() + +if(WITH_OTLP_HTTP_SSL_TLS_PREVIEW AND NOT WITH_OTLP_HTTP_SSL_PREVIEW) + message( + FATAL_ERROR + "WITH_OTLP_HTTP_SSL_TLS_PREVIEW=ON requires WITH_OTLP_HTTP_SSL_PREVIEW=ON" + ) +endif() find_package(Threads) @@ -219,6 +268,12 @@ function(install_windows_deps) endfunction() if(WITH_JAEGER) + if(WITH_NO_DEPRECATED_CODE) + message(FATAL_ERROR "Jaeger is DEPRECATED.") + else() + message(WARNING "Jaeger is DEPRECATED.") + endif() + find_package(Thrift QUIET) if(Thrift_FOUND) find_package(Boost REQUIRED) @@ -314,22 +369,44 @@ if(WITH_OTLP) endif() endif() include(CMakeDependentOption) - if(WITH_OTLP_HTTP OR (NOT DEFINED WITH_OTLP_HTTP AND NOT DEFINED - CACHE{WITH_OTLP_HTTP})) - find_package(CURL) - endif() cmake_dependent_option( WITH_OTLP_GRPC "Whether to include the OTLP gRPC exporter in the SDK" ON "gRPC_FOUND" OFF) - cmake_dependent_option( - WITH_OTLP_HTTP "Whether to include the OTLP http exporter in the SDK" ON - "CURL_FOUND" OFF) message(STATUS "PROTOBUF_PROTOC_EXECUTABLE=${PROTOBUF_PROTOC_EXECUTABLE}") include(cmake/opentelemetry-proto.cmake) endif() +# +# Do we need HTTP CLIENT CURL ? +# + +if(WITH_OTLP_HTTP + OR WITH_ELASTICSEARCH + OR WITH_JAEGER + OR WITH_ZIPKIN + OR BUILD_W3CTRACECONTEXT_TEST + OR WITH_EXAMPLES_HTTP) + set(WITH_HTTP_CLIENT_CURL ON) +else() + set(WITH_HTTP_CLIENT_CURL OFF) +endif() + +# +# Do we need CURL ? +# + +if((NOT WITH_API_ONLY) AND WITH_HTTP_CLIENT_CURL) + # No specific version required. + find_package(CURL REQUIRED) + message(STATUS "Found CURL: ${CURL_LIBRARIES}, version ${CURL_VERSION}") +endif() + +# +# Do we need NLOHMANN_JSON ? +# + if(WITH_ELASTICSEARCH OR WITH_ZIPKIN OR WITH_OTLP_HTTP @@ -340,32 +417,9 @@ if(WITH_ELASTICSEARCH else() set(USE_NLOHMANN_JSON OFF) endif() + if((NOT WITH_API_ONLY) AND USE_NLOHMANN_JSON) - # nlohmann_json package is required for most SDK build configurations - find_package(nlohmann_json QUIET) - set(nlohmann_json_clone FALSE) - if(nlohmann_json_FOUND) - message("Using external nlohmann::json") - elseif(EXISTS ${PROJECT_SOURCE_DIR}/.git - AND EXISTS - ${PROJECT_SOURCE_DIR}/third_party/nlohmann-json/CMakeLists.txt) - message("Trying to use local nlohmann::json from submodule") - set(JSON_BuildTests - OFF - CACHE INTERNAL "") - set(JSON_Install - ON - CACHE INTERNAL "") - # This option allows to link nlohmann_json::nlohmann_json target - add_subdirectory(${PROJECT_SOURCE_DIR}/third_party/nlohmann-json) - # This option allows to add header to include directories - include_directories( - ${PROJECT_SOURCE_DIR}/third_party/nlohmann-json/single_include) - else() - set(nlohmann_json_clone TRUE) - include(cmake/nlohmann-json.cmake) - message("\nnlohmann_json package was not found. Cloning from github") - endif() + include(cmake/nlohmann-json.cmake) endif() if(OTELCPP_MAINTAINER_MODE) @@ -445,6 +499,11 @@ if(OTELCPP_MAINTAINER_MODE) add_compile_options(/wd4267) # Enforced warnings + add_compile_options(/we4265) # 'class': class has virtual functions, but + # destructor is not virtual + add_compile_options(/we5204) # A class with virtual functions has + # non-virtual trivial destructor. + elseif() message(FATAL_ERROR "Building with unknown compiler in maintainer mode.") endif() @@ -488,10 +547,44 @@ endif() include(CMakePackageConfigHelpers) +if(DEFINED OPENTELEMETRY_BUILD_DLL) + if(NOT MSVC) + message(WARNING "Build DLL is supposed to work with MSVC!") + endif() + if(WITH_STL) + message( + WARNING "Build DLL with C++ STL could cause binary incompatibility!") + endif() + add_definitions(-DOPENTELEMETRY_BUILD_EXPORT_DLL) +endif() + include_directories(api/include) add_subdirectory(api) +if(WITH_OPENTRACING) + find_package(OpenTracing CONFIG QUIET) + if(NOT OpenTracing_FOUND) + set(OPENTRACING_DIR "third_party/opentracing-cpp") + message("Trying to use local ${OPENTRACING_DIR} from submodule") + if(EXISTS "${PROJECT_SOURCE_DIR}/${OPENTRACING_DIR}/.git") + set(SAVED_BUILD_TESTING ${BUILD_TESTING}) + set(BUILD_TESTING OFF) + add_subdirectory(${OPENTRACING_DIR}) + set(BUILD_TESTING ${SAVED_BUILD_TESTING}) + else() + message( + FATAL_ERROR + "\nopentracing-cpp package was not found. Please either provide it manually or clone with submodules. " + "To initialize, fetch and checkout any nested submodules, you can use the following command:\n" + "git submodule update --init --recursive") + endif() + else() + message("Using external opentracing-cpp") + endif() + add_subdirectory(opentracing-shim) +endif() + if(NOT WITH_API_ONLY) set(BUILD_TESTING ${BUILD_TESTING}) include_directories(sdk/include) @@ -501,49 +594,55 @@ if(NOT WITH_API_ONLY) add_subdirectory(sdk) add_subdirectory(ext) add_subdirectory(exporters) + if(BUILD_TESTING) add_subdirectory(test_common) endif() if(WITH_EXAMPLES) add_subdirectory(examples) endif() + if(WITH_FUNC_TESTS) + add_subdirectory(functional) + endif() endif() -# Export cmake config and support find_packages(opentelemetry-cpp CONFIG) Write -# config file for find_packages(opentelemetry-cpp CONFIG) -set(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}") -configure_package_config_file( - "${CMAKE_CURRENT_LIST_DIR}/cmake/opentelemetry-cpp-config.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}/${PROJECT_NAME}-config.cmake" - INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" - PATH_VARS OPENTELEMETRY_ABI_VERSION_NO OPENTELEMETRY_VERSION PROJECT_NAME - INCLUDE_INSTALL_DIR CMAKE_INSTALL_LIBDIR - NO_CHECK_REQUIRED_COMPONENTS_MACRO) - -# Write version file for find_packages(opentelemetry-cpp CONFIG) -write_basic_package_version_file( - "${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}/${PROJECT_NAME}-config-version.cmake" - VERSION ${OPENTELEMETRY_VERSION} - COMPATIBILITY ExactVersion) - -install( - FILES +if(OPENTELEMETRY_INSTALL) + # Export cmake config and support find_packages(opentelemetry-cpp CONFIG) + # Write config file for find_packages(opentelemetry-cpp CONFIG) + set(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}") + configure_package_config_file( + "${CMAKE_CURRENT_LIST_DIR}/cmake/opentelemetry-cpp-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}/${PROJECT_NAME}-config.cmake" + INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" + PATH_VARS OPENTELEMETRY_ABI_VERSION_NO OPENTELEMETRY_VERSION PROJECT_NAME + INCLUDE_INSTALL_DIR CMAKE_INSTALL_LIBDIR + NO_CHECK_REQUIRED_COMPONENTS_MACRO) + + # Write version file for find_packages(opentelemetry-cpp CONFIG) + write_basic_package_version_file( "${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}/${PROJECT_NAME}-config-version.cmake" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") - -# Export all components -export( - EXPORT "${PROJECT_NAME}-target" - NAMESPACE "${PROJECT_NAME}::" - FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}/${PROJECT_NAME}-target.cmake" -) -install( - EXPORT "${PROJECT_NAME}-target" - NAMESPACE "${PROJECT_NAME}::" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") - -if(BUILD_PACKAGE) - include(cmake/package.cmake) - include(CPack) + VERSION ${OPENTELEMETRY_VERSION} + COMPATIBILITY ExactVersion) + + install( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}/${PROJECT_NAME}-config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}/${PROJECT_NAME}-config-version.cmake" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") + + # Export all components + export( + EXPORT "${PROJECT_NAME}-target" + NAMESPACE "${PROJECT_NAME}::" + FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}/${PROJECT_NAME}-target.cmake" + ) + install( + EXPORT "${PROJECT_NAME}-target" + NAMESPACE "${PROJECT_NAME}::" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") + + if(BUILD_PACKAGE) + include(cmake/package.cmake) + include(CPack) + endif() endif() diff --git a/DEPRECATED.md b/DEPRECATED.md new file mode 100644 index 0000000000..4125529ef8 --- /dev/null +++ b/DEPRECATED.md @@ -0,0 +1,115 @@ +# Deprecated + +This document lists all the items currently deprecated in opentelemetry-cpp. + +Deprecated items will be removed in the future. + +## Guidelines + +### Maintainer guidelines + +See the [deprecation-process](./docs/deprecation-process.md) + +## [TEMPLATE] + +### New Deprecation Title (Template) + +#### Announcement (Template) + +#### Motivation (Template) + +#### Scope (Template) + +#### Mitigation (Template) + +#### Planned removal (Template) + +## [Platforms] + +N/A + +## [Compilers] + +N/A + +## [Third party dependencies] + +### Jaeger + +See [Jaeger exporter](#jaeger-exporter) + +## [Build tools] + +N/A + +## [Build scripts] + +N/A + +## [opentelemetry-cpp API] + +N/A + +## [opentelemetry-cpp SDK] + +N/A + +## [opentelemetry-cpp Exporter] + +### Jaeger exporter + +#### Announcement (Jaeger) + +* Version: 1.8.2 +* Date: 2023-01-31 +* PR: [DEPRECATION] Deprecate the Jaeger exporter + [#1923](https://github.com/open-telemetry/opentelemetry-cpp/pull/1923) + +#### Motivation (Jaeger) + +The Jaeger client libraries are deprecated, as announced +[here](https://www.jaegertracing.io/docs/1.41/client-libraries/). + +The initial Jaeger announcement in release 1.35 reads as: + +" +We plan to continue accepting pull requests and making new releases of +Jaeger clients through the end of 2021. In January 2022 we will enter a code +freeze period for 6 months, during which time we will no longer accept pull +requests with new features, with the exception of security-related fixes. +After that we will archive the client library repositories and will no +longer accept new changes. +" + +At time of writing, Jan 2023, the client libraries have been archived 6 +months ago already. + +#### Scope (Jaeger) + +The following are deprecated and planned for removal: + +* the API header `opentelemetry/trace/propagation/jaeger.h`, including: + * the C++ class `JaegerPropagator` +* all the code located under `exporters/jaeger/`, including: + * the jaeger exporter C++ class (`JaegerExporter`) + * the related factory (`JaegerExporterFactory`) + * the related options (`JaegerExporterOptions`) +* the jaeger exporter library(`opentelemetry_exporter_jaeger_trace`) +* the jaeger build options in CMake (`WITH_JAEGER`) +* the dependency on thrift + +#### Mitigation (Jaeger) + +Jaeger supports natively the OTLP protocol, starting with jaeger 1.35. + +An application instrumented with opentelemetry needs to change how the SDK +and exporter are configured to replace the Jaeger exporter with the OTLP +exporter (both OTLP HTTP and OTLP GRPC are supported). + +#### Planned removal (Jaeger) + +* Date: July, 2023 + +## [Documentation] + +N/A diff --git a/INSTALL.md b/INSTALL.md index f4b0ffb96d..a5fb65f9ad 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -45,7 +45,7 @@ You can link OpenTelemetry C++ SDK with libraries provided in ### Building as standalone CMake Project -1. Getting the opentelementry-cpp source with its submodules: +1. Getting the opentelemetry-cpp source with its submodules: ```console # Change to the directory where you want to create the code repository @@ -136,7 +136,7 @@ To use the library from a CMake project, you can locate it directly with `find_package` and use the imported targets from generated package configurations. As of now, this will import targets for both API and SDK. In future, there may be separate packages for API and SDK which can be installed - and imported separtely according to need. + and imported separately according to need. ```cmake # CMakeLists.txt @@ -171,7 +171,7 @@ Bazel](https://docs.bazel.build/versions/3.7.0/install.html) guide. ### Building as standalone Bazel Project -1. Getting the opentelementry-cpp source: +1. Getting the opentelemetry-cpp source: ```console # Change to the directory where you want to create the code repository @@ -188,7 +188,7 @@ Bazel](https://docs.bazel.build/versions/3.7.0/install.html) guide. the source code: ```console - $ cd opentelemtry-cpp + $ cd opentelemetry-cpp $ bazel build //... bazel build -- //... -//exporters/otlp/... -//exporters/prometheus/... Extracting Bazel installation... @@ -229,7 +229,7 @@ load("@io_opentelemetry_cpp//bazel:repository.bzl", "opentelemetry_cpp_deps") opentelemetry_cpp_deps() -# Load extra dependencies required for OpenTelemetry +# (required after v1.8.0) Load extra dependencies required for OpenTelemetry load("@io_opentelemetry_cpp//bazel:extra_deps.bzl", "opentelemetry_extra_deps") opentelemetry_extra_deps() @@ -264,14 +264,12 @@ cc_library( ## Building shared libs for Windows -Windows DLL build is not supported. There are some constraints on how C++ DLLs -work on Windows, specifically we can't safely allocate memory in one DLL and -free it in another. For now, OpenTelemetry C++ targets need to be statically -linked into the Windows applications. +Windows DLL build is supported under **preview**. Please check the +[doc](./docs/build-as-dll.md) for more details. -## Generatring binary packages +## Generating binary packages -OpenTelemetry C++ supports generating plateform specific binary packages from CMake +OpenTelemetry C++ supports generating platform specific binary packages from CMake configuration. The packages generated through this mayn't be production ready, and user may have to customize it further before using it as distribution. @@ -285,7 +283,7 @@ configuration ```console $ cd opentelemetry-cpp - $ mkdir build && cd build && cmake -DBUILD_PACKAGE .. + $ mkdir build && cd build && cmake -DBUILD_PACKAGE=ON .. -- Package name: opentelemetry-cpp-1.8.1-ubuntu-20.04-x86_64.deb -- Configuring done @@ -320,6 +318,10 @@ with `vcpkg install opentelemetry-cpp` and follow the then displayed descriptions. Please see the vcpkg project for any issues regarding the packaging. +If you are using [alpine linux](https://www.alpinelinux.org/) you can install +the [opentelemetry-cpp packages](https://pkgs.alpinelinux.org/packages?name=opentelemetry-cpp-*) +with `apk add -X http://dl-cdn.alpinelinux.org/alpine/edge/testing opentelemetry-cpp-dev`. + Please note, these packages are not officially provided and maintained by OpenTelemetry C++ project, and are just listed here to consolidate all such efforts for ease of developers. diff --git a/README.md b/README.md index d12fb87dbd..9166fa690e 100644 --- a/README.md +++ b/README.md @@ -43,14 +43,16 @@ of the current project. | Platform | Build type | |---------------------------------------------------------------------|---------------| -| ubuntu-20.04 (Default GCC Compiler - 9.3.0) | CMake, Bazel | -| ubuntu-18.04 (GCC 4.8 with -std=c++11 flag) | CMake [1] | -| ubuntu-20.04 (Default GCC Compiler - 9.3.0 with -std=c++20 flags) | CMake, Bazel | -| macOS 10.15 (Xcode 12.2) | Bazel | +| ubuntu-22.04 (GCC - 10, 12) | CMake, Bazel | +| ubuntu-20.04 (GCC 4.8 with -std=c++11 flag) | CMake [1] | +| ubuntu-20.04 (GCC 9.4.0) | CMake, Bazel | +| ubuntu-20.04 (Default GCC Compiler - 9.4.0 with -std=c++20 flags) | CMake, Bazel | +| macOS 12.0 (Xcode 14.2) | Bazel | | Windows Server 2019 (Visual Studio Enterprise 2019) | CMake, Bazel | +| Windows Server 2022 (Visual Studio Enterprise 2022) | CMake | [1]: Bazel build is disabled for GCC 4.8, as gRPC library 1.38 and above - (required by OTLP expoter) don't build with this compiler. See gRPC [official + (required by OTLP exporter) don't build with this compiler. See gRPC [official support](https://grpc.io/docs/#official-support) document. CMake build doesn't build OTLP exporter with GCC 4.8. diff --git a/WORKSPACE b/WORKSPACE index 66ab11b55f..a52788ece2 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,16 +1,5 @@ -# Copyright 2019, 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. +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 workspace(name = "io_opentelemetry_cpp") diff --git a/api/BUILD b/api/BUILD index 80ff5ad926..421d26a626 100644 --- a/api/BUILD +++ b/api/BUILD @@ -1,16 +1,5 @@ -# Copyright 2019, 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. +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 load("@bazel_skylib//rules:common_settings.bzl", "bool_flag") diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md deleted file mode 100644 index 854845c8fa..0000000000 --- a/api/CHANGELOG.md +++ /dev/null @@ -1,26 +0,0 @@ -# Release History: opentelemetry-api - -All notable changes to the api 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 API experimental - -### Changed - -### Removed diff --git a/api/CMakeLists.txt b/api/CMakeLists.txt index 826f7f8bca..31863b25e3 100644 --- a/api/CMakeLists.txt +++ b/api/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + add_library(opentelemetry_api INTERFACE) target_include_directories( opentelemetry_api @@ -6,36 +9,43 @@ target_include_directories( set_target_properties(opentelemetry_api PROPERTIES EXPORT_NAME api) -install( - TARGETS opentelemetry_api - EXPORT "${PROJECT_NAME}-target" - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +if(OPENTELEMETRY_INSTALL) + install( + TARGETS opentelemetry_api + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + set(LOGS_EXCLUDE_PATTERN "") + if(NOT WITH_LOGS_PREVIEW) + set(LOGS_EXCLUDE_PATTERN "logs") + endif() -set(LOGS_EXCLUDE_PATTERN "") -if(NOT WITH_LOGS_PREVIEW) - set(LOGS_EXCLUDE_PATTERN "logs") + install( + DIRECTORY include/opentelemetry + DESTINATION include + FILES_MATCHING + PATTERN "*.h" + PATTERN "metrics" EXCLUDE) + + install( + DIRECTORY include/opentelemetry + DESTINATION include + FILES_MATCHING + PATTERN "*.h" + PATTERN "${LOGS_EXCLUDE_PATTERN}" EXCLUDE) endif() -install( - DIRECTORY include/opentelemetry - DESTINATION include - FILES_MATCHING - PATTERN "*.h" - PATTERN "metrics" EXCLUDE) - -install( - DIRECTORY include/opentelemetry - DESTINATION include - FILES_MATCHING - PATTERN "*.h" - PATTERN "${LOGS_EXCLUDE_PATTERN}" EXCLUDE) - if(BUILD_TESTING) add_subdirectory(test) endif() +if(WITH_NO_DEPRECATED_CODE) + target_compile_definitions(opentelemetry_api + INTERFACE OPENTELEMETRY_NO_DEPRECATED_CODE) +endif() + if(WITH_ABSEIL) find_package(absl CONFIG REQUIRED) @@ -73,7 +83,7 @@ if(WITH_LOGS_PREVIEW) target_compile_definitions(opentelemetry_api INTERFACE ENABLE_LOGS_PREVIEW) endif() -if(WITH_NO_GENENV) +if(WITH_NO_GETENV) target_compile_definitions(opentelemetry_api INTERFACE NO_GETENV) endif() @@ -88,6 +98,21 @@ if(WITH_ASYNC_EXPORT_PREVIEW) target_compile_definitions(opentelemetry_api INTERFACE ENABLE_ASYNC_EXPORT) endif() +# A better place should be in sdk, not api +if(WITH_OTLP_HTTP_SSL_PREVIEW) + target_compile_definitions(opentelemetry_api + INTERFACE ENABLE_OTLP_HTTP_SSL_PREVIEW) + target_compile_definitions(opentelemetry_api + INTERFACE ENABLE_HTTP_SSL_PREVIEW) + + if(WITH_OTLP_HTTP_SSL_TLS_PREVIEW) + target_compile_definitions(opentelemetry_api + INTERFACE ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW) + target_compile_definitions(opentelemetry_api + INTERFACE ENABLE_HTTP_SSL_TLS_PREVIEW) + endif() +endif() + if(WITH_METRICS_EXEMPLAR_PREVIEW) target_compile_definitions(opentelemetry_api INTERFACE ENABLE_METRICS_EXEMPLAR_PREVIEW) diff --git a/api/include/opentelemetry/baggage/baggage.h b/api/include/opentelemetry/baggage/baggage.h index 899e4970a6..66a77ed941 100644 --- a/api/include/opentelemetry/baggage/baggage.h +++ b/api/include/opentelemetry/baggage/baggage.h @@ -16,7 +16,7 @@ OPENTELEMETRY_BEGIN_NAMESPACE namespace baggage { -class Baggage +class OPENTELEMETRY_EXPORT Baggage { public: static constexpr size_t kMaxKeyValuePairs = 180; diff --git a/api/include/opentelemetry/common/key_value_iterable.h b/api/include/opentelemetry/common/key_value_iterable.h index f187f75b86..732d361e7b 100644 --- a/api/include/opentelemetry/common/key_value_iterable.h +++ b/api/include/opentelemetry/common/key_value_iterable.h @@ -32,5 +32,32 @@ class KeyValueIterable */ virtual size_t size() const noexcept = 0; }; + +/** + * Supports internal iteration over a collection of key-value pairs. + */ +class NoopKeyValueIterable : public KeyValueIterable +{ +public: + ~NoopKeyValueIterable() override = default; + + /** + * Iterate over key-value pairs + * @param callback a callback to invoke for each key-value. If the callback returns false, + * the iteration is aborted. + * @return true if every key-value pair was iterated over + */ + bool ForEachKeyValue( + nostd::function_ref) const noexcept override + { + return true; + } + + /** + * @return the number of key-value pairs + */ + size_t size() const noexcept override { return 0; } +}; + } // namespace common OPENTELEMETRY_END_NAMESPACE diff --git a/api/include/opentelemetry/common/key_value_iterable_view.h b/api/include/opentelemetry/common/key_value_iterable_view.h index e688ec253f..daea8fce2e 100644 --- a/api/include/opentelemetry/common/key_value_iterable_view.h +++ b/api/include/opentelemetry/common/key_value_iterable_view.h @@ -8,6 +8,8 @@ #include #include "opentelemetry/common/key_value_iterable.h" +#include "opentelemetry/nostd/span.h" +#include "opentelemetry/nostd/string_view.h" #include "opentelemetry/nostd/type_traits.h" #include "opentelemetry/nostd/utility.h" #include "opentelemetry/version.h" @@ -81,5 +83,59 @@ KeyValueIterableView MakeKeyValueIterableView(const T &container) noexcept return KeyValueIterableView(container); } +/** + * Utility function to help to make a attribute view from initializer_list + * + * @param attributes + * @return nostd::span> + */ +inline static nostd::span> +MakeAttributes(std::initializer_list> + attributes) noexcept +{ + return nostd::span>{ + attributes.begin(), attributes.end()}; +} + +/** + * Utility function to help to make a attribute view from a span + * + * @param attributes + * @return nostd::span> + */ +inline static nostd::span> +MakeAttributes( + nostd::span> attributes) noexcept +{ + return attributes; +} + +/** + * Utility function to help to make a attribute view from a KeyValueIterable + * + * @param attributes + * @return common::KeyValueIterable + */ +inline static const common::KeyValueIterable &MakeAttributes( + const common::KeyValueIterable &attributes) noexcept +{ + return attributes; +} + +/** + * Utility function to help to make a attribute view from a key-value iterable object + * + * @param attributes + * @return nostd::span> + */ +template < + class ArgumentType, + nostd::enable_if_t::value> * = nullptr> +inline static common::KeyValueIterableView MakeAttributes( + const ArgumentType &arg) noexcept +{ + return common::KeyValueIterableView(arg); +} + } // namespace common OPENTELEMETRY_END_NAMESPACE diff --git a/api/include/opentelemetry/common/macros.h b/api/include/opentelemetry/common/macros.h index 4741677a74..323e5cdc04 100644 --- a/api/include/opentelemetry/common/macros.h +++ b/api/include/opentelemetry/common/macros.h @@ -3,10 +3,6 @@ #pragma once -#include - -#include "opentelemetry/version.h" - #if !defined(OPENTELEMETRY_LIKELY_IF) && defined(__cplusplus) // GCC 9 has likely attribute but do not support declare it at the beginning of statement # if defined(__has_cpp_attribute) && (defined(__clang__) || !defined(__GNUC__) || __GNUC__ > 9) @@ -92,10 +88,9 @@ // Regex support #if (__GNUC__ == 4 && (__GNUC_MINOR__ == 8 || __GNUC_MINOR__ == 9)) -# define HAVE_WORKING_REGEX 0 +# define OPENTELEMETRY_HAVE_WORKING_REGEX 0 #else -# include -# define HAVE_WORKING_REGEX 1 +# define OPENTELEMETRY_HAVE_WORKING_REGEX 1 #endif /* clang-format off */ @@ -180,3 +175,28 @@ point. # define OPENTELEMETRY_API_SINGLETON #endif + +/* clang-format on */ +// +// The if/elif order matters here. If both OPENTELEMETRY_BUILD_IMPORT_DLL and +// OPENTELEMETRY_BUILD_EXPORT_DLL are defined, the former takes precedence. +// +// TODO: consider define OPENTELEMETRY_EXPORT for cygwin/gcc, see below link. +// https://gcc.gnu.org/wiki/Visibility#How_to_use_the_new_C.2B-.2B-_visibility_support +// +#if defined(_MSC_VER) && defined(OPENTELEMETRY_BUILD_IMPORT_DLL) + +# define OPENTELEMETRY_EXPORT __declspec(dllimport) + +#elif defined(_MSC_VER) && defined(OPENTELEMETRY_BUILD_EXPORT_DLL) + +# define OPENTELEMETRY_EXPORT __declspec(dllexport) + +#else + +// +// build OpenTelemetry as static library or not on Windows. +// +# define OPENTELEMETRY_EXPORT + +#endif diff --git a/api/include/opentelemetry/common/string_util.h b/api/include/opentelemetry/common/string_util.h index 5496f8579e..6dce79f1ba 100644 --- a/api/include/opentelemetry/common/string_util.h +++ b/api/include/opentelemetry/common/string_util.h @@ -14,11 +14,11 @@ class StringUtil public: static nostd::string_view Trim(nostd::string_view str, size_t left, size_t right) noexcept { - while (str[static_cast(left)] == ' ' && left <= right) + while (left <= right && str[static_cast(left)] == ' ') { left++; } - while (str[static_cast(right)] == ' ' && left <= right) + while (left <= right && str[static_cast(right)] == ' ') { right--; } diff --git a/api/include/opentelemetry/context/propagation/global_propagator.h b/api/include/opentelemetry/context/propagation/global_propagator.h index 6d26b84019..460764a74d 100644 --- a/api/include/opentelemetry/context/propagation/global_propagator.h +++ b/api/include/opentelemetry/context/propagation/global_propagator.h @@ -22,7 +22,7 @@ namespace propagation /* Stores the singleton TextMapPropagator */ -class GlobalTextMapPropagator +class OPENTELEMETRY_EXPORT GlobalTextMapPropagator { public: static nostd::shared_ptr GetGlobalPropagator() noexcept diff --git a/api/include/opentelemetry/context/runtime_context.h b/api/include/opentelemetry/context/runtime_context.h index 6d59d9cc44..bec96a9af4 100644 --- a/api/include/opentelemetry/context/runtime_context.h +++ b/api/include/opentelemetry/context/runtime_context.h @@ -37,7 +37,7 @@ class Token * this class and passing an initialized RuntimeContextStorage object to * RuntimeContext::SetRuntimeContextStorage. */ -class RuntimeContextStorage +class OPENTELEMETRY_EXPORT RuntimeContextStorage { public: /** @@ -78,7 +78,7 @@ static RuntimeContextStorage *GetDefaultStorage() noexcept; // Provides a wrapper for propagating the context object globally. // // By default, a thread-local runtime context storage is used. -class RuntimeContext +class OPENTELEMETRY_EXPORT RuntimeContext { public: // Return the current context. diff --git a/api/include/opentelemetry/logs/event_logger.h b/api/include/opentelemetry/logs/event_logger.h new file mode 100644 index 0000000000..654c6f6c69 --- /dev/null +++ b/api/include/opentelemetry/logs/event_logger.h @@ -0,0 +1,94 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once +#ifdef ENABLE_LOGS_PREVIEW + +# include +# include +# include + +# include "opentelemetry/common/macros.h" +# include "opentelemetry/logs/log_record.h" +# include "opentelemetry/logs/logger.h" +# include "opentelemetry/logs/logger_type_traits.h" +# include "opentelemetry/logs/severity.h" +# include "opentelemetry/nostd/shared_ptr.h" +# include "opentelemetry/nostd/string_view.h" +# include "opentelemetry/nostd/unique_ptr.h" +# include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace logs +{ +/** + * Handles event log record creation. + **/ +class EventLogger +{ +public: + virtual ~EventLogger() = default; + + /* Returns the name of the logger */ + virtual const nostd::string_view GetName() noexcept = 0; + + /* Returns the delegate logger of this event logger */ + virtual nostd::shared_ptr GetDelegateLogger() noexcept = 0; + + /** + * Emit a event Log Record object + * + * @param event_name Event name + * @param log_record Log record + */ + virtual void EmitEvent(nostd::string_view event_name, + nostd::unique_ptr &&log_record) noexcept = 0; + + /** + * Emit a event Log Record object with arguments + * + * @param event_name Event name + * @tparam args Arguments which can be used to set data of log record by type. + * Severity -> severity, severity_text + * string_view -> body + * AttributeValue -> body + * SpanContext -> span_id,tace_id and trace_flags + * SpanId -> span_id + * TraceId -> tace_id + * TraceFlags -> trace_flags + * SystemTimestamp -> timestamp + * system_clock::time_point -> timestamp + * KeyValueIterable -> attributes + * Key value iterable container -> attributes + * span> -> attributes(return type of MakeAttributes) + */ + template + void EmitEvent(nostd::string_view event_name, ArgumentType &&... args) + { + nostd::shared_ptr delegate_logger = GetDelegateLogger(); + if (!delegate_logger) + { + return; + } + nostd::unique_ptr log_record = delegate_logger->CreateLogRecord(); + if (!log_record) + { + return; + } + + IgnoreTraitResult( + detail::LogRecordSetterTrait::type>::template Set( + log_record.get(), std::forward(args))...); + + EmitEvent(event_name, std::move(log_record)); + } + +private: + template + void IgnoreTraitResult(ValueType &&...) + {} +}; +} // namespace logs +OPENTELEMETRY_END_NAMESPACE + +#endif diff --git a/api/include/opentelemetry/logs/event_logger_provider.h b/api/include/opentelemetry/logs/event_logger_provider.h new file mode 100644 index 0000000000..8692222c10 --- /dev/null +++ b/api/include/opentelemetry/logs/event_logger_provider.h @@ -0,0 +1,36 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once +#ifdef ENABLE_LOGS_PREVIEW + +# include "opentelemetry/common/key_value_iterable.h" +# include "opentelemetry/common/key_value_iterable_view.h" +# include "opentelemetry/logs/event_logger.h" +# include "opentelemetry/logs/logger.h" +# include "opentelemetry/nostd/shared_ptr.h" +# include "opentelemetry/nostd/string_view.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace logs +{ +/** + * Creates new EventLogger instances. + */ +class EventLoggerProvider +{ +public: + virtual ~EventLoggerProvider() = default; + + /** + * Creates a named EventLogger instance. + * + */ + + virtual nostd::shared_ptr CreateEventLogger( + nostd::shared_ptr delegate_logger, + nostd::string_view event_domain) noexcept = 0; +}; +} // namespace logs +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/api/include/opentelemetry/logs/logger.h b/api/include/opentelemetry/logs/logger.h index a8342e3f71..23aea11143 100644 --- a/api/include/opentelemetry/logs/logger.h +++ b/api/include/opentelemetry/logs/logger.h @@ -4,26 +4,12 @@ #pragma once #ifdef ENABLE_LOGS_PREVIEW -# include -# include -# include - -# include "opentelemetry/common/attribute_value.h" # include "opentelemetry/common/key_value_iterable.h" -# include "opentelemetry/common/key_value_iterable_view.h" -# include "opentelemetry/common/macros.h" -# include "opentelemetry/common/timestamp.h" # include "opentelemetry/logs/log_record.h" +# include "opentelemetry/logs/logger_type_traits.h" # include "opentelemetry/logs/severity.h" -# include "opentelemetry/nostd/shared_ptr.h" -# include "opentelemetry/nostd/span.h" # include "opentelemetry/nostd/string_view.h" -# include "opentelemetry/nostd/type_traits.h" # include "opentelemetry/nostd/unique_ptr.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 @@ -55,44 +41,57 @@ class Logger virtual void EmitLogRecord(nostd::unique_ptr &&log_record) noexcept = 0; /** - * Emit a Log Record object with custom span context + * Emit a Log Record object with arguments * - * @param log_record - */ - virtual void EmitLogRecord(nostd::unique_ptr &&log_record, - const trace::SpanContext &trace_context) + * @param log_record Log record + * @tparam args Arguments which can be used to set data of log record by type. + * Severity -> severity, severity_text + * string_view -> body + * AttributeValue -> body + * SpanContext -> span_id,tace_id and trace_flags + * SpanId -> span_id + * TraceId -> tace_id + * TraceFlags -> trace_flags + * SystemTimestamp -> timestamp + * system_clock::time_point -> timestamp + * KeyValueIterable -> attributes + * Key value iterable container -> attributes + * span> -> attributes(return type of MakeAttributes) + */ + template + void EmitLogRecord(nostd::unique_ptr &&log_record, ArgumentType &&... args) { if (!log_record) { return; } - log_record->SetSpanId(trace_context.span_id()); - log_record->SetTraceId(trace_context.trace_id()); - log_record->SetTraceFlags(trace_context.trace_flags()); + IgnoreTraitResult( + detail::LogRecordSetterTrait::type>::template Set( + log_record.get(), std::forward(args))...); EmitLogRecord(std::move(log_record)); } /** + * Emit a Log Record object with arguments * - * @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). - * @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. - */ - virtual void Log(Severity severity, - nostd::string_view body, - const common::KeyValueIterable &attributes, - trace::TraceId trace_id, - trace::SpanId span_id, - trace::TraceFlags trace_flags, - common::SystemTimestamp timestamp) noexcept + * @tparam args Arguments which can be used to set data of log record by type. + * Severity -> severity, severity_text + * string_view -> body + * AttributeValue -> body + * SpanContext -> span_id,tace_id and trace_flags + * SpanId -> span_id + * TraceId -> tace_id + * TraceFlags -> trace_flags + * SystemTimestamp -> timestamp + * system_clock::time_point -> timestamp + * KeyValueIterable -> attributes + * Key value iterable container -> attributes + * span> -> attributes(return type of MakeAttributes) + */ + template + void EmitLogRecord(ArgumentType &&... args) { nostd::unique_ptr log_record = CreateLogRecord(); if (!log_record) @@ -100,515 +99,159 @@ class Logger return; } - log_record->SetSeverity(severity); - log_record->SetBody(body); - log_record->SetTimestamp(timestamp); - - if (trace_id.IsValid()) - { - log_record->SetTraceId(trace_id); - log_record->SetTraceFlags(trace_flags); - } - - if (span_id.IsValid()) - { - log_record->SetSpanId(span_id); - } - - attributes.ForEachKeyValue( - [&log_record](nostd::string_view key, common::AttributeValue value) noexcept { - log_record->SetAttribute(key, value); - return true; - }); - - EmitLogRecord(std::move(log_record)); - } - - /** - * - * @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). - * @param attributes the attributes, stored as a 2D list of key/value pairs, that are associated - * with the log event. - * @param timestamp the timestamp the log record was created. - * @throws No exceptions under any circumstances. - */ - virtual void Log(Severity severity, - nostd::string_view body, - const common::KeyValueIterable &attributes, - common::SystemTimestamp timestamp) noexcept - { - nostd::unique_ptr log_record = CreateLogRecord(); - if (!log_record) - { - return; - } - - log_record->SetSeverity(severity); - log_record->SetBody(body); - log_record->SetTimestamp(timestamp); - - attributes.ForEachKeyValue( - [&log_record](nostd::string_view key, common::AttributeValue value) noexcept { - log_record->SetAttribute(key, value); - return true; - }); - - EmitLogRecord(std::move(log_record)); - } - - /*** Overloaded methods for KeyValueIterables ***/ - /** - * The secondary base Log(...) method that all other Log(...) overloaded methods except the one - * above will eventually call, in order to create a log record. - */ - template ::value> * = nullptr> - void Log(Severity severity, - nostd::string_view body, - const T &attributes, - trace::TraceId trace_id, - trace::SpanId span_id, - trace::TraceFlags trace_flags, - common::SystemTimestamp timestamp) noexcept - { - Log(severity, body, common::KeyValueIterableView(attributes), trace_id, span_id, trace_flags, - timestamp); - } - - template ::value> * = nullptr> - void Log(Severity severity, - nostd::string_view body, - const T &attributes, - common::SystemTimestamp timestamp) noexcept - { - Log(severity, body, common::KeyValueIterableView(attributes), timestamp); - } - - void Log(Severity severity, - nostd::string_view body, - std::initializer_list> attributes, - trace::TraceId trace_id, - trace::SpanId span_id, - trace::TraceFlags trace_flags, - common::SystemTimestamp timestamp) noexcept - { - return this->Log(severity, body, - nostd::span>{ - attributes.begin(), attributes.end()}, - trace_id, span_id, trace_flags, timestamp); - } - - /** Wrapper methods that the user could call for convenience when logging **/ - - /** - * Writes a log. - * @param severity The severity of the log - * @param message The message to log - */ - void Log(Severity severity, nostd::string_view message) noexcept - { - this->Log(severity, message, - nostd::span>{}, - std::chrono::system_clock::now()); - } - - /** - * Writes a log. - * @param severity The severity of the log - * @param attributes The attributes of the log as a key/value object - */ - template ::value> * = nullptr> - void Log(Severity severity, const T &attributes) noexcept - { - this->Log(severity, "", attributes, std::chrono::system_clock::now()); - } - - /** - * Writes a log. - * @param severity The severity of the log - * @param message The message to log - * @param attributes The attributes of the log as a key/value object - */ - template ::value> * = nullptr> - void Log(Severity severity, nostd::string_view message, const T &attributes) noexcept - { - this->Log(severity, message, attributes, std::chrono::system_clock::now()); - } - - /** - * Writes a log. - * @param severity The severity of the log - * @param attributes The attributes of the log as an initializer list - */ - void Log(Severity severity, - std::initializer_list> - attributes) noexcept - { - this->Log(severity, "", attributes, std::chrono::system_clock::now()); - } - - /** - * Writes a log. - * @param severity The severity of the log - * @param message The message to log - * @param attributes The attributes of the log as an initializer list - */ - void Log(Severity severity, - nostd::string_view message, - std::initializer_list> - attributes) noexcept - { - this->Log(severity, message, attributes, std::chrono::system_clock::now()); - } - - /** - * Writes a log. - * @param severity The severity of the log - * @param attributes The attributes, stored as a 2D list of key/value pairs, that are associated - * with the log event - */ - void Log(Severity severity, const common::KeyValueIterable &attributes) noexcept - { - this->Log(severity, "", attributes, std::chrono::system_clock::now()); - } - - /** - * Writes a log. - * @param severity The severity of the log - * @param message The message to log - * @param attributes The attributes, stored as a 2D list of key/value pairs, that are associated - * with the log event - */ - void Log(Severity severity, - nostd::string_view message, - const common::KeyValueIterable &attributes) noexcept - { - this->Log(severity, message, attributes, std::chrono::system_clock::now()); - } - - /** Trace severity overloads **/ - - /** - * Writes a log with a severity of trace. - * @param message The message to log - */ - void Trace(nostd::string_view message) noexcept { this->Log(Severity::kTrace, message); } - - /** - * Writes a log with a severity of trace. - * @param attributes The attributes of the log as a key/value object - */ - template ::value> * = nullptr> - void Trace(const T &attributes) noexcept - { - this->Log(Severity::kTrace, attributes); - } - - /** - * Writes a log with a severity of trace. - * @param message The message of the log - * @param attributes The attributes of the log as a key/value object - */ - template ::value> * = nullptr> - void Trace(nostd::string_view message, const T &attributes) noexcept - { - this->Log(Severity::kTrace, message, attributes); + EmitLogRecord(std::move(log_record), std::forward(args)...); } /** * Writes a log with a severity of trace. - * @param attributes The attributes of the log as an initializer list - */ - void Trace(std::initializer_list> - attributes) noexcept - { - this->Log(Severity::kTrace, attributes); - } - - /** - * Writes a log with a severity of trace. - * @param message The message of the log - * @param attributes The attributes of the log as an initializer list - */ - void Trace(nostd::string_view message, - std::initializer_list> - attributes) noexcept - { - this->Log(Severity::kTrace, message, attributes); - } - - /** Debug severity overloads **/ - - /** - * Writes a log with a severity of debug. - * @param message The message to log - */ - void Debug(nostd::string_view message) noexcept { this->Log(Severity::kDebug, message); } - - /** - * Writes a log with a severity of debug. - * @param attributes The attributes of the log as a key/value object - */ - template ::value> * = nullptr> - void Debug(const T &attributes) noexcept - { - this->Log(Severity::kDebug, attributes); - } - - /** - * Writes a log with a severity of debug. - * @param message The message of the log - * @param attributes The attributes of the log as a key/value object + * @tparam args Arguments which can be used to set data of log record by type. + * string_view -> body + * AttributeValue -> body + * SpanContext -> span_id,tace_id and trace_flags + * SpanId -> span_id + * TraceId -> tace_id + * TraceFlags -> trace_flags + * SystemTimestamp -> timestamp + * system_clock::time_point -> timestamp + * KeyValueIterable -> attributes + * Key value iterable container -> attributes + * span> -> attributes(return type of MakeAttributes) */ - template ::value> * = nullptr> - void Debug(nostd::string_view message, const T &attributes) noexcept + template + void Trace(ArgumentType &&... args) noexcept { - this->Log(Severity::kDebug, message, attributes); + static_assert( + !detail::LogRecordHasType::type...>::value, + "Severity is already set."); + this->EmitLogRecord(Severity::kTrace, std::forward(args)...); } /** * Writes a log with a severity of debug. - * @param attributes The attributes of the log as an initializer list - */ - void Debug(std::initializer_list> - attributes) noexcept - { - this->Log(Severity::kDebug, attributes); - } - - /** - * Writes a log with a severity of debug. - * @param message The message of the log - * @param attributes The attributes of the log as an initializer list - */ - void Debug(nostd::string_view message, - std::initializer_list> - attributes) noexcept - { - this->Log(Severity::kDebug, message, attributes); - } - - /** Info severity overloads **/ - - /** - * Writes a log with a severity of info. - * @param message The message to log - */ - void Info(nostd::string_view message) noexcept { this->Log(Severity::kInfo, message); } - - /** - * Writes a log with a severity of info. - * @param attributes The attributes of the log as a key/value object - */ - template ::value> * = nullptr> - void Info(const T &attributes) noexcept - { - this->Log(Severity::kInfo, attributes); - } - - /** - * Writes a log with a severity of info. - * @param message The message of the log - * @param attributes The attributes of the log as a key/value object - */ - template ::value> * = nullptr> - void Info(nostd::string_view message, const T &attributes) noexcept - { - this->Log(Severity::kInfo, message, attributes); - } - - /** - * Writes a log with a severity of info. - * @param attributes The attributes of the log as an initializer list + * @tparam args Arguments which can be used to set data of log record by type. + * string_view -> body + * AttributeValue -> body + * SpanContext -> span_id,tace_id and trace_flags + * SpanId -> span_id + * TraceId -> tace_id + * TraceFlags -> trace_flags + * SystemTimestamp -> timestamp + * system_clock::time_point -> timestamp + * KeyValueIterable -> attributes + * Key value iterable container -> attributes + * span> -> attributes(return type of MakeAttributes) */ - void Info(std::initializer_list> - attributes) noexcept + template + void Debug(ArgumentType &&... args) noexcept { - this->Log(Severity::kInfo, attributes); + static_assert( + !detail::LogRecordHasType::type...>::value, + "Severity is already set."); + this->EmitLogRecord(Severity::kDebug, std::forward(args)...); } /** * Writes a log with a severity of info. - * @param message The message of the log - * @param attributes The attributes of the log as an initializer list - */ - void Info(nostd::string_view message, - std::initializer_list> - attributes) noexcept - { - this->Log(Severity::kInfo, message, attributes); - } - - /** Warn severity overloads **/ - - /** - * Writes a log with a severity of warn. - * @param message The message to log - */ - void Warn(nostd::string_view message) noexcept { this->Log(Severity::kWarn, message); } - - /** - * Writes a log with a severity of warn. - * @param attributes The attributes of the log as a key/value object - */ - template ::value> * = nullptr> - void Warn(const T &attributes) noexcept - { - this->Log(Severity::kWarn, attributes); - } - - /** - * Writes a log with a severity of warn. - * @param message The message of the log - * @param attributes The attributes of the log as a key/value object - */ - template ::value> * = nullptr> - void Warn(nostd::string_view message, const T &attributes) noexcept - { - this->Log(Severity::kWarn, message, attributes); - } - - /** - * Writes a log with a severity of warn. - * @param attributes The attributes of the log as an initializer list + * @tparam args Arguments which can be used to set data of log record by type. + * string_view -> body + * AttributeValue -> body + * SpanContext -> span_id,tace_id and trace_flags + * SpanId -> span_id + * TraceId -> tace_id + * TraceFlags -> trace_flags + * SystemTimestamp -> timestamp + * system_clock::time_point -> timestamp + * KeyValueIterable -> attributes + * Key value iterable container -> attributes + * span> -> attributes(return type of MakeAttributes) */ - void Warn(std::initializer_list> - attributes) noexcept + template + void Info(ArgumentType &&... args) noexcept { - this->Log(Severity::kWarn, attributes); + static_assert( + !detail::LogRecordHasType::type...>::value, + "Severity is already set."); + this->EmitLogRecord(Severity::kInfo, std::forward(args)...); } /** * Writes a log with a severity of warn. - * @param message The message of the log - * @param attributes The attributes of the log as an initializer list - */ - void Warn(nostd::string_view message, - std::initializer_list> - attributes) noexcept - { - this->Log(Severity::kWarn, message, attributes); - } - - /** Error severity overloads **/ - - /** - * Writes a log with a severity of error. - * @param message The message to log - */ - void Error(nostd::string_view message) noexcept { this->Log(Severity::kError, message); } - - /** - * Writes a log with a severity of error. - * @param attributes The attributes of the log as a key/value object - */ - template ::value> * = nullptr> - void Error(const T &attributes) noexcept - { - this->Log(Severity::kError, attributes); - } - - /** - * Writes a log with a severity of error. - * @param message The message of the log - * @param attributes The attributes of the log as a key/value object - */ - template ::value> * = nullptr> - void Error(nostd::string_view message, const T &attributes) noexcept - { - this->Log(Severity::kError, message, attributes); - } - - /** - * Writes a log with a severity of error. - * @param attributes The attributes of the log as an initializer list + * @tparam args Arguments which can be used to set data of log record by type. + * string_view -> body + * AttributeValue -> body + * SpanContext -> span_id,tace_id and trace_flags + * SpanId -> span_id + * TraceId -> tace_id + * TraceFlags -> trace_flags + * SystemTimestamp -> timestamp + * system_clock::time_point -> timestamp + * KeyValueIterable -> attributes + * Key value iterable container -> attributes + * span> -> attributes(return type of MakeAttributes) */ - void Error(std::initializer_list> - attributes) noexcept + template + void Warn(ArgumentType &&... args) noexcept { - this->Log(Severity::kError, attributes); + static_assert( + !detail::LogRecordHasType::type...>::value, + "Severity is already set."); + this->EmitLogRecord(Severity::kWarn, std::forward(args)...); } /** * Writes a log with a severity of error. - * @param message The message of the log - * @param attributes The attributes of the log as an initializer list - */ - void Error(nostd::string_view message, - std::initializer_list> - attributes) noexcept - { - this->Log(Severity::kError, message, attributes); - } - - /** Fatal severity overloads **/ - - /** - * Writes a log with a severity of fatal. - * @param message The message to log + * @tparam args Arguments which can be used to set data of log record by type. + * string_view -> body + * AttributeValue -> body + * SpanContext -> span_id,tace_id and trace_flags + * SpanId -> span_id + * TraceId -> tace_id + * TraceFlags -> trace_flags + * SystemTimestamp -> timestamp + * system_clock::time_point -> timestamp + * KeyValueIterable -> attributes + * Key value iterable container -> attributes + * span> -> attributes(return type of MakeAttributes) */ - void Fatal(nostd::string_view message) noexcept { this->Log(Severity::kFatal, message); } - - /** - * Writes a log with a severity of fatal. - * @param attributes The attributes of the log as a key/value object - */ - template ::value> * = nullptr> - void Fatal(const T &attributes) noexcept + template + void Error(ArgumentType &&... args) noexcept { - this->Log(Severity::kFatal, attributes); + static_assert( + !detail::LogRecordHasType::type...>::value, + "Severity is already set."); + this->EmitLogRecord(Severity::kError, std::forward(args)...); } /** * Writes a log with a severity of fatal. - * @param message The message of the log - * @param attributes The attributes of the log as a key/value object - */ - template ::value> * = nullptr> - void Fatal(nostd::string_view message, const T &attributes) noexcept - { - this->Log(Severity::kFatal, message, attributes); - } - - /** - * Writes a log with a severity of fatal. - * @param attributes The attributes of the log as an initializer list - */ - void Fatal(std::initializer_list> - attributes) noexcept - { - this->Log(Severity::kFatal, attributes); - } - - /** - * Writes a log with a severity of fatal. - * @param message The message of the log - * @param attributes The attributes of the log as an initializer list - */ - void Fatal(nostd::string_view message, - std::initializer_list> - attributes) noexcept - { - this->Log(Severity::kFatal, message, attributes); - } + * @tparam args Arguments which can be used to set data of log record by type. + * string_view -> body + * AttributeValue -> body + * SpanContext -> span_id,tace_id and trace_flags + * SpanId -> span_id + * TraceId -> tace_id + * TraceFlags -> trace_flags + * SystemTimestamp -> timestamp + * system_clock::time_point -> timestamp + * KeyValueIterable -> attributes + * Key value iterable container -> attributes + * span> -> attributes(return type of MakeAttributes) + */ + template + void Fatal(ArgumentType &&... args) noexcept + { + static_assert( + !detail::LogRecordHasType::type...>::value, + "Severity is already set."); + this->EmitLogRecord(Severity::kFatal, std::forward(args)...); + } + +private: + template + void IgnoreTraitResult(ValueType &&...) + {} }; } // namespace logs OPENTELEMETRY_END_NAMESPACE -#endif +#endif // end of ENABLE_LOGS_PREVIEW diff --git a/api/include/opentelemetry/logs/logger_provider.h b/api/include/opentelemetry/logs/logger_provider.h index 5f1795c8ea..7979ab202a 100644 --- a/api/include/opentelemetry/logs/logger_provider.h +++ b/api/include/opentelemetry/logs/logger_provider.h @@ -2,8 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 #pragma once + #ifdef ENABLE_LOGS_PREVIEW +# include "opentelemetry/common/key_value_iterable.h" +# include "opentelemetry/common/key_value_iterable_view.h" # include "opentelemetry/logs/logger.h" # include "opentelemetry/nostd/shared_ptr.h" # include "opentelemetry/nostd/string_view.h" @@ -14,7 +17,7 @@ namespace logs /** * Creates new Logger instances. */ -class LoggerProvider +class OPENTELEMETRY_EXPORT LoggerProvider { public: virtual ~LoggerProvider() = default; @@ -30,18 +33,41 @@ class LoggerProvider * */ - virtual nostd::shared_ptr 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 = "") = 0; - - virtual nostd::shared_ptr GetLogger(nostd::string_view logger_name, - nostd::span args, - nostd::string_view library_name, - nostd::string_view library_version = "", - nostd::string_view schema_url = "") = 0; + virtual nostd::shared_ptr GetLogger( + nostd::string_view logger_name, + nostd::string_view library_name, + nostd::string_view library_version = "", + nostd::string_view schema_url = "", + bool include_trace_context = true, + const common::KeyValueIterable &attributes = common::NoopKeyValueIterable()) = 0; + + nostd::shared_ptr GetLogger( + nostd::string_view logger_name, + nostd::string_view library_name, + nostd::string_view library_version, + nostd::string_view schema_url, + bool include_trace_context, + std::initializer_list> attributes) + { + return GetLogger(logger_name, library_name, library_version, schema_url, include_trace_context, + nostd::span>{ + attributes.begin(), attributes.end()}); + } + + template ::value> * = nullptr> + nostd::shared_ptr GetLogger(nostd::string_view logger_name, + nostd::string_view library_name, + nostd::string_view library_version, + nostd::string_view schema_url, + bool include_trace_context, + const T &attributes) + { + return GetLogger(logger_name, library_name, library_version, schema_url, include_trace_context, + common::KeyValueIterableView(attributes)); + } }; } // namespace logs OPENTELEMETRY_END_NAMESPACE -#endif + +#endif // ENABLE_LOGS_PREVIEW diff --git a/api/include/opentelemetry/logs/logger_type_traits.h b/api/include/opentelemetry/logs/logger_type_traits.h new file mode 100644 index 0000000000..8736c03f7f --- /dev/null +++ b/api/include/opentelemetry/logs/logger_type_traits.h @@ -0,0 +1,192 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once +#ifdef ENABLE_LOGS_PREVIEW + +# include +# include + +# include "opentelemetry/common/attribute_value.h" +# include "opentelemetry/common/key_value_iterable.h" +# include "opentelemetry/common/timestamp.h" +# include "opentelemetry/logs/log_record.h" +# include "opentelemetry/logs/severity.h" +# include "opentelemetry/nostd/shared_ptr.h" +# include "opentelemetry/nostd/span.h" +# include "opentelemetry/nostd/string_view.h" +# include "opentelemetry/nostd/type_traits.h" +# include "opentelemetry/nostd/unique_ptr.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 logs +{ +namespace detail +{ +template +struct LogRecordSetterTrait; + +template <> +struct LogRecordSetterTrait +{ + template + inline static LogRecord *Set(LogRecord *log_record, ArgumentType &&arg) noexcept + { + log_record->SetSeverity(std::forward(arg)); + + return log_record; + } +}; + +template <> +struct LogRecordSetterTrait +{ + template + inline static LogRecord *Set(LogRecord *log_record, ArgumentType &&arg) noexcept + { + log_record->SetSpanId(arg.span_id()); + log_record->SetTraceId(arg.trace_id()); + log_record->SetTraceFlags(arg.trace_flags()); + + return log_record; + } +}; + +template <> +struct LogRecordSetterTrait +{ + template + inline static LogRecord *Set(LogRecord *log_record, ArgumentType &&arg) noexcept + { + log_record->SetSpanId(std::forward(arg)); + + return log_record; + } +}; + +template <> +struct LogRecordSetterTrait +{ + template + inline static LogRecord *Set(LogRecord *log_record, ArgumentType &&arg) noexcept + { + log_record->SetTraceId(std::forward(arg)); + + return log_record; + } +}; + +template <> +struct LogRecordSetterTrait +{ + template + inline static LogRecord *Set(LogRecord *log_record, ArgumentType &&arg) noexcept + { + log_record->SetTraceFlags(std::forward(arg)); + + return log_record; + } +}; + +template <> +struct LogRecordSetterTrait +{ + template + inline static LogRecord *Set(LogRecord *log_record, ArgumentType &&arg) noexcept + { + log_record->SetTimestamp(std::forward(arg)); + + return log_record; + } +}; + +template <> +struct LogRecordSetterTrait +{ + template + inline static LogRecord *Set(LogRecord *log_record, ArgumentType &&arg) noexcept + { + log_record->SetTimestamp(common::SystemTimestamp(std::forward(arg))); + + return log_record; + } +}; + +template <> +struct LogRecordSetterTrait +{ + template + inline static LogRecord *Set(LogRecord *log_record, ArgumentType &&arg) noexcept + { + arg.ForEachKeyValue( + [&log_record](nostd::string_view key, common::AttributeValue value) noexcept { + log_record->SetAttribute(key, value); + return true; + }); + + return log_record; + } +}; + +template +struct LogRecordSetterTrait +{ + template ::value || + std::is_convertible::value, + void> * = nullptr> + inline static LogRecord *Set(LogRecord *log_record, ArgumentType &&arg) noexcept + { + log_record->SetBody(std::forward(arg)); + + return log_record; + } + + template ::value, bool> + * = nullptr> + inline static LogRecord *Set(LogRecord *log_record, ArgumentType &&arg) noexcept + { + return LogRecordSetterTrait::template Set( + log_record, std::forward(arg)); + } + + template ::value, int> * = + nullptr> + inline static LogRecord *Set(LogRecord *log_record, ArgumentType &&arg) noexcept + { + for (auto &argv : arg) + { + log_record->SetAttribute(argv.first, argv.second); + } + + return log_record; + } +}; + +template +struct LogRecordHasType; + +template +struct LogRecordHasType : public std::false_type +{}; + +template +struct LogRecordHasType + : public std::conditional::value, + std::true_type, + LogRecordHasType>::type +{}; + +} // namespace detail + +} // namespace logs +OPENTELEMETRY_END_NAMESPACE + +#endif diff --git a/api/include/opentelemetry/logs/noop.h b/api/include/opentelemetry/logs/noop.h index d8941510da..5061003274 100644 --- a/api/include/opentelemetry/logs/noop.h +++ b/api/include/opentelemetry/logs/noop.h @@ -15,6 +15,7 @@ # include "opentelemetry/common/key_value_iterable.h" # include "opentelemetry/common/timestamp.h" # include "opentelemetry/context/runtime_context.h" +# include "opentelemetry/logs/event_logger_provider.h" # include "opentelemetry/logs/logger.h" # include "opentelemetry/logs/logger_provider.h" # include "opentelemetry/logs/severity.h" @@ -60,26 +61,54 @@ class NoopLoggerProvider final : public opentelemetry::logs::LoggerProvider {} nostd::shared_ptr 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 */) override + nostd::string_view /* schema_url */, + bool /* include_trace_context */, + const common::KeyValueIterable & /* attributes */) override { return logger_; } - nostd::shared_ptr GetLogger(nostd::string_view /* logger_name */, - nostd::span /* args */, - nostd::string_view /* library_name */, - nostd::string_view /* library_version */, - nostd::string_view /* schema_url */) override +private: + nostd::shared_ptr logger_; +}; + +class NoopEventLogger final : public EventLogger +{ +public: + NoopEventLogger() : logger_{nostd::shared_ptr(new NoopLogger())} {} + + const nostd::string_view GetName() noexcept override { return "noop event logger"; } + + nostd::shared_ptr GetDelegateLogger() noexcept override { return logger_; } + + void EmitEvent(nostd::string_view, nostd::unique_ptr &&) noexcept override {} + +private: + nostd::shared_ptr logger_; +}; + +/** + * No-op implementation of a EventLoggerProvider. + */ +class NoopEventLoggerProvider final : public EventLoggerProvider +{ +public: + NoopEventLoggerProvider() : event_logger_{nostd::shared_ptr(new NoopEventLogger())} + {} + + nostd::shared_ptr CreateEventLogger( + nostd::shared_ptr /*delegate_logger*/, + nostd::string_view /*event_domain*/) noexcept override { - return logger_; + return event_logger_; } private: - nostd::shared_ptr logger_; + nostd::shared_ptr event_logger_; }; + } // namespace logs OPENTELEMETRY_END_NAMESPACE #endif diff --git a/api/include/opentelemetry/logs/provider.h b/api/include/opentelemetry/logs/provider.h index 6f4b76fbd7..e361c1e670 100644 --- a/api/include/opentelemetry/logs/provider.h +++ b/api/include/opentelemetry/logs/provider.h @@ -8,6 +8,7 @@ # include "opentelemetry/common/macros.h" # include "opentelemetry/common/spin_lock_mutex.h" +# include "opentelemetry/logs/event_logger_provider.h" # include "opentelemetry/logs/logger_provider.h" # include "opentelemetry/logs/noop.h" # include "opentelemetry/nostd/shared_ptr.h" @@ -18,7 +19,7 @@ namespace logs /** * Stores the singleton global LoggerProvider. */ -class Provider +class OPENTELEMETRY_EXPORT Provider { public: /** @@ -42,6 +43,27 @@ class Provider GetProvider() = tp; } + /** + * Returns the singleton EventLoggerProvider. + * + * By default, a no-op EventLoggerProvider is returned. This will never return a + * nullptr EventLoggerProvider. + */ + static nostd::shared_ptr GetEventLoggerProvider() noexcept + { + std::lock_guard guard(GetLock()); + return nostd::shared_ptr(GetEventProvider()); + } + + /** + * Changes the singleton EventLoggerProvider. + */ + static void SetEventLoggerProvider(nostd::shared_ptr tp) noexcept + { + std::lock_guard guard(GetLock()); + GetEventProvider() = tp; + } + private: OPENTELEMETRY_API_SINGLETON static nostd::shared_ptr &GetProvider() noexcept { @@ -49,6 +71,13 @@ class Provider return provider; } + OPENTELEMETRY_API_SINGLETON static nostd::shared_ptr + &GetEventProvider() noexcept + { + static nostd::shared_ptr provider(new NoopEventLoggerProvider); + return provider; + } + OPENTELEMETRY_API_SINGLETON static common::SpinLockMutex &GetLock() noexcept { static common::SpinLockMutex lock; diff --git a/api/include/opentelemetry/metrics/meter.h b/api/include/opentelemetry/metrics/meter.h index 13d4a8e700..52fa511b95 100644 --- a/api/include/opentelemetry/metrics/meter.h +++ b/api/include/opentelemetry/metrics/meter.h @@ -101,7 +101,7 @@ class Meter /** * Creates a Asynchronouse (Observable) Gauge with the passed characteristics and returns a - * shared_ptr to that Observable Counter + * shared_ptr to that Observable Gauge * * @param name the name of the new Observable Gauge. * @param description a brief description of what the Observable Gauge is used for. diff --git a/api/include/opentelemetry/nostd/detail/all.h b/api/include/opentelemetry/nostd/detail/all.h index dc12a5a5f9..deaf3ac6f2 100644 --- a/api/include/opentelemetry/nostd/detail/all.h +++ b/api/include/opentelemetry/nostd/detail/all.h @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + #pragma once #include diff --git a/api/include/opentelemetry/nostd/detail/decay.h b/api/include/opentelemetry/nostd/detail/decay.h index 23aaaee2eb..a6cb111243 100644 --- a/api/include/opentelemetry/nostd/detail/decay.h +++ b/api/include/opentelemetry/nostd/detail/decay.h @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + #pragma once #include diff --git a/api/include/opentelemetry/nostd/detail/dependent_type.h b/api/include/opentelemetry/nostd/detail/dependent_type.h index 0f58bcf7f7..5bba09ff88 100644 --- a/api/include/opentelemetry/nostd/detail/dependent_type.h +++ b/api/include/opentelemetry/nostd/detail/dependent_type.h @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + #pragma once #include diff --git a/api/include/opentelemetry/nostd/detail/functional.h b/api/include/opentelemetry/nostd/detail/functional.h index a3546f2bee..437f92f0ad 100644 --- a/api/include/opentelemetry/nostd/detail/functional.h +++ b/api/include/opentelemetry/nostd/detail/functional.h @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + #pragma once #include diff --git a/api/include/opentelemetry/nostd/detail/invoke.h b/api/include/opentelemetry/nostd/detail/invoke.h index 629fb9c966..a0c010a8f9 100644 --- a/api/include/opentelemetry/nostd/detail/invoke.h +++ b/api/include/opentelemetry/nostd/detail/invoke.h @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + #pragma once #include diff --git a/api/include/opentelemetry/nostd/detail/trait.h b/api/include/opentelemetry/nostd/detail/trait.h index d4ed09cbb5..90a568c4f4 100644 --- a/api/include/opentelemetry/nostd/detail/trait.h +++ b/api/include/opentelemetry/nostd/detail/trait.h @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + #pragma once #include diff --git a/api/include/opentelemetry/nostd/detail/type_pack_element.h b/api/include/opentelemetry/nostd/detail/type_pack_element.h index 0c522dd280..280d24e94a 100644 --- a/api/include/opentelemetry/nostd/detail/type_pack_element.h +++ b/api/include/opentelemetry/nostd/detail/type_pack_element.h @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + #pragma once #include diff --git a/api/include/opentelemetry/nostd/detail/valueless.h b/api/include/opentelemetry/nostd/detail/valueless.h index 2a89b575e2..3b2ca7f7cf 100644 --- a/api/include/opentelemetry/nostd/detail/valueless.h +++ b/api/include/opentelemetry/nostd/detail/valueless.h @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + #pragma once #include "opentelemetry/version.h" diff --git a/api/include/opentelemetry/nostd/detail/variant_alternative.h b/api/include/opentelemetry/nostd/detail/variant_alternative.h index 70486cfc1a..cc0da9c8c1 100644 --- a/api/include/opentelemetry/nostd/detail/variant_alternative.h +++ b/api/include/opentelemetry/nostd/detail/variant_alternative.h @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + #pragma once #include diff --git a/api/include/opentelemetry/nostd/detail/variant_fwd.h b/api/include/opentelemetry/nostd/detail/variant_fwd.h index 6d2d1ef9ec..6bae9659ec 100644 --- a/api/include/opentelemetry/nostd/detail/variant_fwd.h +++ b/api/include/opentelemetry/nostd/detail/variant_fwd.h @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + #pragma once #include "opentelemetry/version.h" diff --git a/api/include/opentelemetry/nostd/detail/variant_size.h b/api/include/opentelemetry/nostd/detail/variant_size.h index 0814710305..d8986a222b 100644 --- a/api/include/opentelemetry/nostd/detail/variant_size.h +++ b/api/include/opentelemetry/nostd/detail/variant_size.h @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + #pragma once #include diff --git a/api/include/opentelemetry/nostd/detail/void.h b/api/include/opentelemetry/nostd/detail/void.h index e8d4a48c01..1b4c3b4f7d 100644 --- a/api/include/opentelemetry/nostd/detail/void.h +++ b/api/include/opentelemetry/nostd/detail/void.h @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + #pragma once #include "opentelemetry/version.h" diff --git a/api/include/opentelemetry/nostd/shared_ptr.h b/api/include/opentelemetry/nostd/shared_ptr.h index 75b184f61c..4f7dd86bb4 100644 --- a/api/include/opentelemetry/nostd/shared_ptr.h +++ b/api/include/opentelemetry/nostd/shared_ptr.h @@ -103,13 +103,11 @@ class shared_ptr new (buffer_.data) shared_ptr_wrapper{std::move(ptr_)}; } -# ifndef HAVE_CPP_STDLIB shared_ptr(std::unique_ptr &&other) noexcept { std::shared_ptr ptr_(other.release()); new (buffer_.data) shared_ptr_wrapper{std::move(ptr_)}; } -# endif ~shared_ptr() { wrapper().~shared_ptr_wrapper(); } diff --git a/api/include/opentelemetry/trace/noop.h b/api/include/opentelemetry/trace/noop.h index 5532aacbe6..8a9b13b7a1 100644 --- a/api/include/opentelemetry/trace/noop.h +++ b/api/include/opentelemetry/trace/noop.h @@ -27,7 +27,7 @@ namespace trace /** * No-op implementation of Span. This class should not be used directly. */ -class NoopSpan final : public Span +class OPENTELEMETRY_EXPORT NoopSpan final : public Span { public: explicit NoopSpan(const std::shared_ptr &tracer) noexcept @@ -76,7 +76,8 @@ class NoopSpan final : public Span /** * No-op implementation of Tracer. */ -class NoopTracer final : public Tracer, public std::enable_shared_from_this +class OPENTELEMETRY_EXPORT NoopTracer final : public Tracer, + public std::enable_shared_from_this { public: // Tracer @@ -101,7 +102,7 @@ class NoopTracer final : public Tracer, public std::enable_shared_from_this is deprecated." +#endif + #include "detail/hex.h" #include "detail/string.h" #include "opentelemetry/context/propagation/text_map_propagator.h" @@ -17,7 +21,7 @@ namespace propagation static const nostd::string_view kJaegerTraceHeader = "uber-trace-id"; -class JaegerPropagator : public context::propagation::TextMapPropagator +class OPENTELEMETRY_DEPRECATED JaegerPropagator : public context::propagation::TextMapPropagator { public: void Inject(context::propagation::TextMapCarrier &carrier, diff --git a/api/include/opentelemetry/trace/provider.h b/api/include/opentelemetry/trace/provider.h index e59c5f9512..aff94d4d0e 100644 --- a/api/include/opentelemetry/trace/provider.h +++ b/api/include/opentelemetry/trace/provider.h @@ -17,7 +17,7 @@ namespace trace /** * Stores the singleton global TracerProvider. */ -class Provider +class OPENTELEMETRY_EXPORT Provider { public: /** diff --git a/api/include/opentelemetry/trace/semantic_conventions.h b/api/include/opentelemetry/trace/semantic_conventions.h index c7339fe22b..ecada99a41 100644 --- a/api/include/opentelemetry/trace/semantic_conventions.h +++ b/api/include/opentelemetry/trace/semantic_conventions.h @@ -21,7 +21,7 @@ namespace SemanticConventions /** * The URL of the OpenTelemetry schema for these keys and values. */ -static constexpr const char *kSchemaUrl = "https://opentelemetry.io/schemas/1.16.0"; +static constexpr const char *kSchemaUrl = "https://opentelemetry.io/schemas/1.20.0"; /** * The type of the exception (its fully-qualified class name, if applicable). The dynamic type of @@ -40,6 +40,33 @@ static constexpr const char *kExceptionMessage = "exception.message"; */ static constexpr const char *kExceptionStacktrace = "exception.stacktrace"; +/** + * HTTP request method. + */ +static constexpr const char *kHttpMethod = "http.method"; + +/** + * HTTP response status code. + */ +static constexpr const char *kHttpStatusCode = "http.status_code"; + +/** + * The URI scheme identifying the used protocol. + */ +static constexpr const char *kHttpScheme = "http.scheme"; + +/** + * The matched route (path template in the format used by the respective server framework). See note +below + * + *

Notes: +

  • MUST NOT be populated when this is not supported by the HTTP server framework as the +route attribute should have low-cardinality and the URI path can NOT substitute it. SHOULD include +the application +root if there is one.
+ */ +static constexpr const char *kHttpRoute = "http.route"; + /** * The name identifies the event. */ @@ -54,12 +81,23 @@ unrelated events. */ static constexpr const char *kEventDomain = "event.domain"; +/** + * A unique identifier for the Log Record. + * + *

Notes: +

  • If an id is provided, other log records with the same id will be considered duplicates +and can be removed safely. This means, that two distinguishable log records MUST have different +values. The id MAY be an Universally Unique Lexicographically +Sortable Identifier (ULID), but other identifiers (e.g. UUID) may be used as needed.
+ */ +static constexpr const char *kLogRecordUid = "log.record.uid"; + /** * The full invoked ARN as provided on the {@code Context} passed to the function ({@code Lambda-Runtime-Invoked-Function-Arn} header on the {@code /runtime/invocation/next} applicable). * *

Notes: -

  • This may be different from {@code faas.id} if an alias is involved.
+
  • This may be different from {@code cloud.resource_id} if an alias is involved.
*/ static constexpr const char *kAwsLambdaInvokedArn = "aws.lambda.invoked_arn"; @@ -143,9 +181,6 @@ static constexpr const char *kDbName = "db.name"; /** * The database statement being executed. - * - *

Notes: -

  • The value may be sanitized to exclude sensitive information.
*/ static constexpr const char *kDbStatement = "db.statement"; @@ -243,6 +278,46 @@ static constexpr const char *kDbMongodbCollection = "db.mongodb.collection"; */ static constexpr const char *kDbSqlTable = "db.sql.table"; +/** + * Unique Cosmos client instance id. + */ +static constexpr const char *kDbCosmosdbClientId = "db.cosmosdb.client_id"; + +/** + * CosmosDB Operation Type. + */ +static constexpr const char *kDbCosmosdbOperationType = "db.cosmosdb.operation_type"; + +/** + * Cosmos client connection mode. + */ +static constexpr const char *kDbCosmosdbConnectionMode = "db.cosmosdb.connection_mode"; + +/** + * Cosmos DB container name. + */ +static constexpr const char *kDbCosmosdbContainer = "db.cosmosdb.container"; + +/** + * Request payload size in bytes + */ +static constexpr const char *kDbCosmosdbRequestContentLength = "db.cosmosdb.request_content_length"; + +/** + * Cosmos DB status code. + */ +static constexpr const char *kDbCosmosdbStatusCode = "db.cosmosdb.status_code"; + +/** + * Cosmos DB sub status code. + */ +static constexpr const char *kDbCosmosdbSubStatusCode = "db.cosmosdb.sub_status_code"; + +/** + * RU consumed for that operation + */ +static constexpr const char *kDbCosmosdbRequestCharge = "db.cosmosdb.request_charge"; + /** * Name of the code, either "OK" or "ERROR". MUST NOT be set if the status code * is UNSET. @@ -255,7 +330,7 @@ static constexpr const char *kOtelStatusCode = "otel.status_code"; static constexpr const char *kOtelStatusDescription = "otel.status_description"; /** - * Type of the trigger which caused this function execution. + * Type of the trigger which caused this function invocation. * *

Notes:

  • For the server/consumer span on the incoming side, @@ -268,9 +343,9 @@ lambda, which is often HTTP).
static constexpr const char *kFaasTrigger = "faas.trigger"; /** - * The execution ID of the current function execution. + * The invocation ID of the current function invocation. */ -static constexpr const char *kFaasExecution = "faas.execution"; +static constexpr const char *kFaasInvocationId = "faas.invocation_id"; /** * The name of the source on which the triggering operation was performed. For example, in Cloud @@ -343,6 +418,30 @@ static constexpr const char *kFaasInvokedProvider = "faas.invoked_provider"; */ static constexpr const char *kFaasInvokedRegion = "faas.invoked_region"; +/** + * The unique identifier of the feature flag. + */ +static constexpr const char *kFeatureFlagKey = "feature_flag.key"; + +/** + * The name of the service provider that performs the flag evaluation. + */ +static constexpr const char *kFeatureFlagProviderName = "feature_flag.provider_name"; + +/** + * SHOULD be a semantic identifier for a value. If one is unavailable, a stringified version of the +value can be used. + * + *

Notes: +

  • A semantic identifier, commonly referred to as a variant, provides a means +for referring to a value without including the value itself. This can +provide additional context for understanding the meaning behind a value. +For example, the variant {@code red} maybe be used for the value {@code #c05543}.
  • A +stringified version of the value can be used in situations where a semantic identifier is +unavailable. String representation of the value should be determined by the implementer.
+ */ +static constexpr const char *kFeatureFlagVariant = "feature_flag.variant"; + /** * Transport protocol used. See note below. */ @@ -351,18 +450,18 @@ static constexpr const char *kNetTransport = "net.transport"; /** * Application layer protocol used. The value SHOULD be normalized to lowercase. */ -static constexpr const char *kNetAppProtocolName = "net.app.protocol.name"; +static constexpr const char *kNetProtocolName = "net.protocol.name"; /** * Version of the application layer protocol used. See note below. * *

Notes: -

  • {@code net.app.protocol.version} refers to the version of the protocol used and might be +
    • {@code net.protocol.version} refers to the version of the protocol used and might be different from the protocol client's version. If the HTTP client used has a version of {@code 0.27.2}, but sends HTTP version {@code 1.1}, this attribute should be set to {@code 1.1}.
    */ -static constexpr const char *kNetAppProtocolVersion = "net.app.protocol.version"; +static constexpr const char *kNetProtocolVersion = "net.protocol.version"; /** * Remote socket peer name. @@ -516,29 +615,10 @@ static constexpr const char *kCodeFilepath = "code.filepath"; static constexpr const char *kCodeLineno = "code.lineno"; /** - * HTTP request method. - */ -static constexpr const char *kHttpMethod = "http.method"; - -/** - * HTTP response status code. - */ -static constexpr const char *kHttpStatusCode = "http.status_code"; - -/** - * Kind of HTTP protocol used. - * - *

    Notes: -

    • If {@code net.transport} is not specified, it can be assumed to be {@code IP.TCP} except - if {@code http.flavor} is {@code QUIC}, in which case {@code IP.UDP} is assumed.
    - */ -static constexpr const char *kHttpFlavor = "http.flavor"; - -/** - * Value of the HTTP - * User-Agent header sent by the client. + * The column number in {@code code.filepath} best representing the operation. It SHOULD point + * within the code unit named in {@code code.function}. */ -static constexpr const char *kHttpUserAgent = "http.user_agent"; +static constexpr const char *kCodeColumn = "code.column"; /** * The size of the request payload body in bytes. This is the number of bytes transferred excluding @@ -577,27 +657,11 @@ static constexpr const char *kHttpUrl = "http.url"; */ static constexpr const char *kHttpResendCount = "http.resend_count"; -/** - * The URI scheme identifying the used protocol. - */ -static constexpr const char *kHttpScheme = "http.scheme"; - /** * The full request target as passed in a HTTP request line or equivalent. */ static constexpr const char *kHttpTarget = "http.target"; -/** - * The matched route (path template in the format used by the respective server framework). See note - below - * - *

    Notes: -

    • 'http.route' MUST NOT be populated when this is not supported by the HTTP server - framework as the route attribute should have low-cardinality and the URI path can NOT substitute - it.
    - */ -static constexpr const char *kHttpRoute = "http.route"; - /** * The IP address of the original client behind all proxies, if known (e.g. from X-Forwarded-For). @@ -615,6 +679,12 @@ the closest proxy.
*/ static constexpr const char *kHttpClientIp = "http.client_ip"; +/** + * The AWS request ID as returned in the response headers {@code x-amz-request-id} or {@code + * x-amz-requestid}. + */ +static constexpr const char *kAwsRequestId = "aws.request_id"; + /** * The keys in the {@code RequestItems} object field. */ @@ -733,6 +803,117 @@ static constexpr const char *kAwsDynamodbAttributeDefinitions = static constexpr const char *kAwsDynamodbGlobalSecondaryIndexUpdates = "aws.dynamodb.global_secondary_index_updates"; +/** + * The S3 bucket name the request refers to. Corresponds to the {@code --bucket} parameter of the S3 API operations. + * + *

Notes: +

  • The {@code bucket} attribute is applicable to all S3 operations that reference a bucket, +i.e. that require the bucket name as a mandatory parameter. This applies to almost all S3 operations +except {@code list-buckets}.
+ */ +static constexpr const char *kAwsS3Bucket = "aws.s3.bucket"; + +/** + * The S3 object key the request refers to. Corresponds to the {@code --key} parameter of the S3 API operations. + * + *

Notes: +

+ */ +static constexpr const char *kAwsS3Key = "aws.s3.key"; + +/** + * The source object (in the form {@code bucket}/{@code key}) for the copy operation. + * + *

Notes: +

+ */ +static constexpr const char *kAwsS3CopySource = "aws.s3.copy_source"; + +/** + * Upload ID that identifies the multipart upload. + * + *

Notes: +

+ */ +static constexpr const char *kAwsS3UploadId = "aws.s3.upload_id"; + +/** + * The delete request container that specifies the objects to be deleted. + * + *

Notes: +

+ */ +static constexpr const char *kAwsS3Delete = "aws.s3.delete"; + +/** + * The part number of the part being uploaded in a multipart-upload operation. This is a positive +integer between 1 and 10,000. + * + *

Notes: +

+ */ +static constexpr const char *kAwsS3PartNumber = "aws.s3.part_number"; + /** * The name of the operation being executed. */ @@ -752,88 +933,138 @@ static constexpr const char *kGraphqlOperationType = "graphql.operation.type"; static constexpr const char *kGraphqlDocument = "graphql.document"; /** - * A string identifying the messaging system. + * A value used by the messaging system as an identifier for the message, represented as a string. */ -static constexpr const char *kMessagingSystem = "messaging.system"; +static constexpr const char *kMessagingMessageId = "messaging.message.id"; + +/** + * The conversation ID identifying the conversation to which the + * message belongs, represented as a string. Sometimes called "Correlation ID". + */ +static constexpr const char *kMessagingMessageConversationId = "messaging.message.conversation_id"; /** - * The message destination name. This might be equal to the span name but is required nevertheless. + * The (uncompressed) size of the message payload in bytes. Also use this attribute if it is unknown + * whether the compressed or uncompressed payload size is reported. */ -static constexpr const char *kMessagingDestination = "messaging.destination"; +static constexpr const char *kMessagingMessagePayloadSizeBytes = + "messaging.message.payload_size_bytes"; /** - * The kind of message destination + * The compressed size of the message payload in bytes. */ -static constexpr const char *kMessagingDestinationKind = "messaging.destination_kind"; +static constexpr const char *kMessagingMessagePayloadCompressedSizeBytes = + "messaging.message.payload_compressed_size_bytes"; /** - * A boolean that is true if the message destination is temporary. + * The message destination name + * + *

Notes: +

  • Destination name SHOULD uniquely identify a specific queue, topic or other entity within +the broker. If the broker does not have such notion, the destination name SHOULD uniquely identify +the broker.
*/ -static constexpr const char *kMessagingTempDestination = "messaging.temp_destination"; +static constexpr const char *kMessagingDestinationName = "messaging.destination.name"; /** - * The name of the transport protocol. + * Low cardinality representation of the messaging destination name + * + *

Notes: +

  • Destination names could be constructed from templates. An example would be a destination + name involving a user name or product id. Although the destination name in this case is of high + cardinality, the underlying template is of low cardinality and can be effectively used for grouping + and aggregation.
*/ -static constexpr const char *kMessagingProtocol = "messaging.protocol"; +static constexpr const char *kMessagingDestinationTemplate = "messaging.destination.template"; /** - * The version of the transport protocol. + * A boolean that is true if the message destination is temporary and might not exist anymore after + * messages are processed. */ -static constexpr const char *kMessagingProtocolVersion = "messaging.protocol_version"; +static constexpr const char *kMessagingDestinationTemporary = "messaging.destination.temporary"; /** - * Connection string. + * A boolean that is true if the message destination is anonymous (could be unnamed or have + * auto-generated name). */ -static constexpr const char *kMessagingUrl = "messaging.url"; +static constexpr const char *kMessagingDestinationAnonymous = "messaging.destination.anonymous"; /** - * A value used by the messaging system as an identifier for the message, represented as a string. + * The message source name + * + *

Notes: +

  • Source name SHOULD uniquely identify a specific queue, topic, or other entity within the +broker. If the broker does not have such notion, the source name SHOULD uniquely identify the +broker.
*/ -static constexpr const char *kMessagingMessageId = "messaging.message_id"; +static constexpr const char *kMessagingSourceName = "messaging.source.name"; /** - * The conversation ID identifying the conversation to which the - * message belongs, represented as a string. Sometimes called "Correlation ID". + * Low cardinality representation of the messaging source name + * + *

Notes: +

  • Source names could be constructed from templates. An example would be a source name + involving a user name or product id. Although the source name in this case is of high cardinality, + the underlying template is of low cardinality and can be effectively used for grouping and + aggregation.
*/ -static constexpr const char *kMessagingConversationId = "messaging.conversation_id"; +static constexpr const char *kMessagingSourceTemplate = "messaging.source.template"; /** - * The (uncompressed) size of the message payload in bytes. Also use this attribute if it is unknown - * whether the compressed or uncompressed payload size is reported. + * A boolean that is true if the message source is temporary and might not exist anymore after + * messages are processed. */ -static constexpr const char *kMessagingMessagePayloadSizeBytes = - "messaging.message_payload_size_bytes"; +static constexpr const char *kMessagingSourceTemporary = "messaging.source.temporary"; /** - * The compressed size of the message payload in bytes. + * A boolean that is true if the message source is anonymous (could be unnamed or have + * auto-generated name). */ -static constexpr const char *kMessagingMessagePayloadCompressedSizeBytes = - "messaging.message_payload_compressed_size_bytes"; +static constexpr const char *kMessagingSourceAnonymous = "messaging.source.anonymous"; + +/** + * A string identifying the messaging system. + */ +static constexpr const char *kMessagingSystem = "messaging.system"; /** - * A string identifying the kind of message consumption as defined in the Operation names section above. If the operation is "send", - * this attribute MUST NOT be set, since the operation can be inferred from the span kind in that - * case. + * A string identifying the kind of messaging operation as defined in the Operation names section above. + * + *

Notes: +

  • If a custom value is used, it MUST be of low cardinality.
*/ static constexpr const char *kMessagingOperation = "messaging.operation"; +/** + * The number of messages sent, received, or processed in the scope of the batching operation. + * + *

Notes: +

  • Instrumentations SHOULD NOT set {@code messaging.batch.message_count} on spans that + operate with a single message. When a messaging client library supports both batch and + single-message API for the same operation, instrumentations SHOULD use {@code + messaging.batch.message_count} for batching APIs and SHOULD NOT use it for single-message + APIs.
+ */ +static constexpr const char *kMessagingBatchMessageCount = "messaging.batch.message_count"; + /** * The identifier for the consumer receiving a message. For Kafka, set it to {@code - * {messaging.kafka.consumer_group} - {messaging.kafka.client_id}}, if both are present, or only - * {@code messaging.kafka.consumer_group}. For brokers, such as RabbitMQ and Artemis, set it to the + * {messaging.kafka.consumer.group} - {messaging.kafka.client_id}}, if both are present, or only + * {@code messaging.kafka.consumer.group}. For brokers, such as RabbitMQ and Artemis, set it to the * {@code client_id} of the client consuming the message. */ -static constexpr const char *kMessagingConsumerId = "messaging.consumer_id"; +static constexpr const char *kMessagingConsumerId = "messaging.consumer.id"; /** * RabbitMQ message routing key. */ -static constexpr const char *kMessagingRabbitmqRoutingKey = "messaging.rabbitmq.routing_key"; +static constexpr const char *kMessagingRabbitmqDestinationRoutingKey = + "messaging.rabbitmq.destination.routing_key"; /** * Message keys in Kafka are used for grouping alike messages to ensure they're processed on the - same partition. They differ from {@code messaging.message_id} in that they're not unique. If the + same partition. They differ from {@code messaging.message.id} in that they're not unique. If the key is {@code null}, the attribute MUST NOT be set. * *

Notes: @@ -841,13 +1072,13 @@ static constexpr const char *kMessagingRabbitmqRoutingKey = "messaging.rabbitmq. attribute. If the key has no unambiguous, canonical string form, don't include its value. */ -static constexpr const char *kMessagingKafkaMessageKey = "messaging.kafka.message_key"; +static constexpr const char *kMessagingKafkaMessageKey = "messaging.kafka.message.key"; /** * Name of the Kafka Consumer Group that is handling the message. Only applies to consumers, not * producers. */ -static constexpr const char *kMessagingKafkaConsumerGroup = "messaging.kafka.consumer_group"; +static constexpr const char *kMessagingKafkaConsumerGroup = "messaging.kafka.consumer.group"; /** * Client Id for the Consumer or Producer that is handling the message. @@ -857,7 +1088,13 @@ static constexpr const char *kMessagingKafkaClientId = "messaging.kafka.client_i /** * Partition the message is sent to. */ -static constexpr const char *kMessagingKafkaPartition = "messaging.kafka.partition"; +static constexpr const char *kMessagingKafkaDestinationPartition = + "messaging.kafka.destination.partition"; + +/** + * Partition the message is received from. + */ +static constexpr const char *kMessagingKafkaSourcePartition = "messaging.kafka.source.partition"; /** * The offset of a record in the corresponding Kafka partition. @@ -867,7 +1104,7 @@ static constexpr const char *kMessagingKafkaMessageOffset = "messaging.kafka.mes /** * A boolean that is true if the message is a tombstone. */ -static constexpr const char *kMessagingKafkaTombstone = "messaging.kafka.tombstone"; +static constexpr const char *kMessagingKafkaMessageTombstone = "messaging.kafka.message.tombstone"; /** * Namespace of RocketMQ resources, resources in different namespaces are individual. @@ -888,35 +1125,35 @@ static constexpr const char *kMessagingRocketmqClientId = "messaging.rocketmq.cl /** * The timestamp in milliseconds that the delay message is expected to be delivered to consumer. */ -static constexpr const char *kMessagingRocketmqDeliveryTimestamp = - "messaging.rocketmq.delivery_timestamp"; +static constexpr const char *kMessagingRocketmqMessageDeliveryTimestamp = + "messaging.rocketmq.message.delivery_timestamp"; /** * The delay time level for delay message, which determines the message delay time. */ -static constexpr const char *kMessagingRocketmqDelayTimeLevel = - "messaging.rocketmq.delay_time_level"; +static constexpr const char *kMessagingRocketmqMessageDelayTimeLevel = + "messaging.rocketmq.message.delay_time_level"; /** * It is essential for FIFO message. Messages that belong to the same message group are always * processed one by one within the same consumer group. */ -static constexpr const char *kMessagingRocketmqMessageGroup = "messaging.rocketmq.message_group"; +static constexpr const char *kMessagingRocketmqMessageGroup = "messaging.rocketmq.message.group"; /** * Type of message. */ -static constexpr const char *kMessagingRocketmqMessageType = "messaging.rocketmq.message_type"; +static constexpr const char *kMessagingRocketmqMessageType = "messaging.rocketmq.message.type"; /** * The secondary classifier of message besides topic. */ -static constexpr const char *kMessagingRocketmqMessageTag = "messaging.rocketmq.message_tag"; +static constexpr const char *kMessagingRocketmqMessageTag = "messaging.rocketmq.message.tag"; /** * Key(s) of message, another way to mark message besides message id. */ -static constexpr const char *kMessagingRocketmqMessageKeys = "messaging.rocketmq.message_keys"; +static constexpr const char *kMessagingRocketmqMessageKeys = "messaging.rocketmq.message.keys"; /** * Model of message consumption. This only applies to consumer spans. @@ -982,6 +1219,62 @@ static constexpr const char *kRpcJsonrpcErrorCode = "rpc.jsonrpc.error_code"; */ static constexpr const char *kRpcJsonrpcErrorMessage = "rpc.jsonrpc.error_message"; +/** + * Whether this is a received or sent message. + */ +static constexpr const char *kMessageType = "message.type"; + +/** + * MUST be calculated as two different counters starting from {@code 1} one for sent messages and + one for received message. + * + *

Notes: +

  • This way we guarantee that the values will be consistent between different + implementations.
+ */ +static constexpr const char *kMessageId = "message.id"; + +/** + * Compressed size of the message in bytes. + */ +static constexpr const char *kMessageCompressedSize = "message.compressed_size"; + +/** + * Uncompressed size of the message in bytes. + */ +static constexpr const char *kMessageUncompressedSize = "message.uncompressed_size"; + +/** + * The error codes of the Connect + * request. Error codes are always string values. + */ +static constexpr const char *kRpcConnectRpcErrorCode = "rpc.connect_rpc.error_code"; + +/** + * SHOULD be set to true if the exception event is recorded at a point where it is known that the +exception is escaping the scope of the span. + * + *

Notes: +

  • An exception is considered to have escaped (or left) the scope of a span, +if that span is ended while the exception is still logically "in flight". +This may be actually "in flight" in some languages (e.g. if the exception +is passed to a Context manager's {@code __exit__} method in Python) but will +usually be caught at the point of recording the exception in most languages.
  • It is usually +not possible to determine at the point where an exception is thrown whether it will escape the scope +of a span. However, it is trivial to know that an exception will escape, if one checks for an active +exception just before ending the span, as done in the example +above.
  • It follows that an exception may still escape the scope of the span even if the +{@code exception.escaped} attribute was not set or set to false, since the event might have been +recorded at a time where it was not clear whether the exception will escape.
+ */ +static constexpr const char *kExceptionEscaped = "exception.escaped"; + +/** + * Value of the HTTP + * User-Agent header sent by the client. + */ +static constexpr const char *kUserAgentOriginal = "user_agent.original"; + // Enum definitions namespace EventDomainValues { @@ -1007,6 +1300,8 @@ namespace DbSystemValues static constexpr const char *kOtherSql = "other_sql"; /** Microsoft SQL Server. */ static constexpr const char *kMssql = "mssql"; +/** Microsoft SQL Server Compact. */ +static constexpr const char *kMssqlcompact = "mssqlcompact"; /** MySQL. */ static constexpr const char *kMysql = "mysql"; /** Oracle Database. */ @@ -1099,6 +1394,12 @@ static constexpr const char *kMemcached = "memcached"; static constexpr const char *kCockroachdb = "cockroachdb"; /** OpenSearch. */ static constexpr const char *kOpensearch = "opensearch"; +/** ClickHouse. */ +static constexpr const char *kClickhouse = "clickhouse"; +/** Cloud Spanner. */ +static constexpr const char *kSpanner = "spanner"; +/** Trino. */ +static constexpr const char *kTrino = "trino"; } // namespace DbSystemValues namespace DbCassandraConsistencyLevelValues @@ -1127,6 +1428,48 @@ static constexpr const char *kSerial = "serial"; static constexpr const char *kLocalSerial = "local_serial"; } // namespace DbCassandraConsistencyLevelValues +namespace DbCosmosdbOperationTypeValues +{ +/** invalid. */ +static constexpr const char *kInvalid = "Invalid"; +/** create. */ +static constexpr const char *kCreate = "Create"; +/** patch. */ +static constexpr const char *kPatch = "Patch"; +/** read. */ +static constexpr const char *kRead = "Read"; +/** read_feed. */ +static constexpr const char *kReadFeed = "ReadFeed"; +/** delete. */ +static constexpr const char *kDelete = "Delete"; +/** replace. */ +static constexpr const char *kReplace = "Replace"; +/** execute. */ +static constexpr const char *kExecute = "Execute"; +/** query. */ +static constexpr const char *kQuery = "Query"; +/** head. */ +static constexpr const char *kHead = "Head"; +/** head_feed. */ +static constexpr const char *kHeadFeed = "HeadFeed"; +/** upsert. */ +static constexpr const char *kUpsert = "Upsert"; +/** batch. */ +static constexpr const char *kBatch = "Batch"; +/** query_plan. */ +static constexpr const char *kQueryPlan = "QueryPlan"; +/** execute_javascript. */ +static constexpr const char *kExecuteJavascript = "ExecuteJavaScript"; +} // namespace DbCosmosdbOperationTypeValues + +namespace DbCosmosdbConnectionModeValues +{ +/** Gateway (HTTP) connections mode. */ +static constexpr const char *kGateway = "gateway"; +/** Direct connection. */ +static constexpr const char *kDirect = "direct"; +} // namespace DbCosmosdbConnectionModeValues + namespace OtelStatusCodeValues { /** The operation has been validated by an Application developer or Operator to have completed @@ -1258,22 +1601,6 @@ static constexpr const char *kNrnsa = "nrnsa"; static constexpr const char *kLteCa = "lte_ca"; } // namespace NetHostConnectionSubtypeValues -namespace HttpFlavorValues -{ -/** HTTP/1.0. */ -static constexpr const char *kHttp10 = "1.0"; -/** HTTP/1.1. */ -static constexpr const char *kHttp11 = "1.1"; -/** HTTP/2. */ -static constexpr const char *kHttp20 = "2.0"; -/** HTTP/3. */ -static constexpr const char *kHttp30 = "3.0"; -/** SPDY protocol. */ -static constexpr const char *kSpdy = "SPDY"; -/** QUIC protocol. */ -static constexpr const char *kQuic = "QUIC"; -} // namespace HttpFlavorValues - namespace GraphqlOperationTypeValues { /** GraphQL query. */ @@ -1284,16 +1611,10 @@ static constexpr const char *kMutation = "mutation"; static constexpr const char *kSubscription = "subscription"; } // namespace GraphqlOperationTypeValues -namespace MessagingDestinationKindValues -{ -/** A message sent to a queue. */ -static constexpr const char *kQueue = "queue"; -/** A message sent to a topic. */ -static constexpr const char *kTopic = "topic"; -} // namespace MessagingDestinationKindValues - namespace MessagingOperationValues { +/** publish. */ +static constexpr const char *kPublish = "publish"; /** receive. */ static constexpr const char *kReceive = "receive"; /** process. */ @@ -1330,6 +1651,8 @@ static constexpr const char *kJavaRmi = "java_rmi"; static constexpr const char *kDotnetWcf = "dotnet_wcf"; /** Apache Dubbo. */ static constexpr const char *kApacheDubbo = "apache_dubbo"; +/** Connect RPC. */ +static constexpr const char *kConnectRpc = "connect_rpc"; } // namespace RpcSystemValues namespace RpcGrpcStatusCodeValues @@ -1370,6 +1693,50 @@ static constexpr const int kDataLoss = 15; static constexpr const int kUnauthenticated = 16; } // namespace RpcGrpcStatusCodeValues +namespace MessageTypeValues +{ +/** sent. */ +static constexpr const char *kSent = "SENT"; +/** received. */ +static constexpr const char *kReceived = "RECEIVED"; +} // namespace MessageTypeValues + +namespace RpcConnectRpcErrorCodeValues +{ +/** cancelled. */ +static constexpr const char *kCancelled = "cancelled"; +/** unknown. */ +static constexpr const char *kUnknown = "unknown"; +/** invalid_argument. */ +static constexpr const char *kInvalidArgument = "invalid_argument"; +/** deadline_exceeded. */ +static constexpr const char *kDeadlineExceeded = "deadline_exceeded"; +/** not_found. */ +static constexpr const char *kNotFound = "not_found"; +/** already_exists. */ +static constexpr const char *kAlreadyExists = "already_exists"; +/** permission_denied. */ +static constexpr const char *kPermissionDenied = "permission_denied"; +/** resource_exhausted. */ +static constexpr const char *kResourceExhausted = "resource_exhausted"; +/** failed_precondition. */ +static constexpr const char *kFailedPrecondition = "failed_precondition"; +/** aborted. */ +static constexpr const char *kAborted = "aborted"; +/** out_of_range. */ +static constexpr const char *kOutOfRange = "out_of_range"; +/** unimplemented. */ +static constexpr const char *kUnimplemented = "unimplemented"; +/** internal. */ +static constexpr const char *kInternal = "internal"; +/** unavailable. */ +static constexpr const char *kUnavailable = "unavailable"; +/** data_loss. */ +static constexpr const char *kDataLoss = "data_loss"; +/** unauthenticated. */ +static constexpr const char *kUnauthenticated = "unauthenticated"; +} // namespace RpcConnectRpcErrorCodeValues + } // namespace SemanticConventions } // namespace trace OPENTELEMETRY_END_NAMESPACE diff --git a/api/include/opentelemetry/trace/span_id.h b/api/include/opentelemetry/trace/span_id.h index 63d2f36894..19511040df 100644 --- a/api/include/opentelemetry/trace/span_id.h +++ b/api/include/opentelemetry/trace/span_id.h @@ -1,16 +1,5 @@ -// Copyright 2019, 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. +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 #pragma once diff --git a/api/include/opentelemetry/trace/trace_state.h b/api/include/opentelemetry/trace/trace_state.h index 496cde30c4..28fd126fea 100644 --- a/api/include/opentelemetry/trace/trace_state.h +++ b/api/include/opentelemetry/trace/trace_state.h @@ -7,20 +7,16 @@ #include #include -#include -#if (__GNUC__ == 4 && (__GNUC_MINOR__ == 8 || __GNUC_MINOR__ == 9)) -# define HAVE_WORKING_REGEX 0 -#else -# define HAVE_WORKING_REGEX 1 -#endif - #include "opentelemetry/common/kv_properties.h" -#include "opentelemetry/common/macros.h" #include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/nostd/span.h" #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/nostd/unique_ptr.h" +#if defined(OPENTELEMETRY_HAVE_WORKING_REGEX) +# include +#endif + OPENTELEMETRY_BEGIN_NAMESPACE namespace trace { @@ -33,7 +29,7 @@ namespace trace * For more information, see the W3C Trace Context specification: * https://www.w3.org/TR/trace-context */ -class TraceState +class OPENTELEMETRY_EXPORT TraceState { public: static constexpr int kKeyMaxSize = 256; @@ -212,7 +208,7 @@ class TraceState */ static bool IsValidKey(nostd::string_view key) { -#if HAVE_WORKING_REGEX +#if OPENTELEMETRY_HAVE_WORKING_REGEX return IsValidKeyRegEx(key); #else return IsValidKeyNonRegEx(key); @@ -225,7 +221,7 @@ class TraceState */ static bool IsValidValue(nostd::string_view value) { -#if HAVE_WORKING_REGEX +#if OPENTELEMETRY_HAVE_WORKING_REGEX return IsValidValueRegEx(value); #else return IsValidValueNonRegEx(value); diff --git a/api/include/opentelemetry/trace/tracer_provider.h b/api/include/opentelemetry/trace/tracer_provider.h index 2dae74ce14..9d3125db40 100644 --- a/api/include/opentelemetry/trace/tracer_provider.h +++ b/api/include/opentelemetry/trace/tracer_provider.h @@ -13,7 +13,7 @@ namespace trace /** * Creates new Tracer instances. */ -class TracerProvider +class OPENTELEMETRY_EXPORT TracerProvider { public: virtual ~TracerProvider() = default; diff --git a/api/include/opentelemetry/version.h b/api/include/opentelemetry/version.h index 35a0a2baff..be7b677d85 100644 --- a/api/include/opentelemetry/version.h +++ b/api/include/opentelemetry/version.h @@ -3,10 +3,15 @@ #pragma once +#include "opentelemetry/common/macros.h" #include "opentelemetry/detail/preprocessor.h" #define OPENTELEMETRY_ABI_VERSION_NO 1 -#define OPENTELEMETRY_VERSION "1.8.1" +#define OPENTELEMETRY_VERSION "1.9.0" +#define OPENTELEMETRY_VERSION_MAJOR 1 +#define OPENTELEMETRY_VERSION_MINOR 9 +#define OPENTELEMETRY_VERSION_PATCH 0 + #define OPENTELEMETRY_ABI_VERSION OPENTELEMETRY_STRINGIFY(OPENTELEMETRY_ABI_VERSION_NO) // clang-format off diff --git a/api/test/CMakeLists.txt b/api/test/CMakeLists.txt index 0d2b00804f..2d051cc726 100644 --- a/api/test/CMakeLists.txt +++ b/api/test/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + add_subdirectory(core) add_subdirectory(context) add_subdirectory(plugin) diff --git a/api/test/baggage/BUILD b/api/test/baggage/BUILD index a6a4ae2165..a3783a63c0 100644 --- a/api/test/baggage/BUILD +++ b/api/test/baggage/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark") cc_test( diff --git a/api/test/baggage/CMakeLists.txt b/api/test/baggage/CMakeLists.txt index cb58f169fb..0b0fee52ac 100644 --- a/api/test/baggage/CMakeLists.txt +++ b/api/test/baggage/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + include(GoogleTest) foreach(testname baggage_test) diff --git a/api/test/baggage/propagation/BUILD b/api/test/baggage/propagation/BUILD index 1cd4371c16..2b820ed3c8 100644 --- a/api/test/baggage/propagation/BUILD +++ b/api/test/baggage/propagation/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark") cc_test( diff --git a/api/test/baggage/propagation/CMakeLists.txt b/api/test/baggage/propagation/CMakeLists.txt index 3b7bd3d07a..b4142ead8a 100644 --- a/api/test/baggage/propagation/CMakeLists.txt +++ b/api/test/baggage/propagation/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + foreach(testname baggage_propagator_test) add_executable(${testname} "${testname}.cc") target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} diff --git a/api/test/common/BUILD b/api/test/common/BUILD index 438a9bbf6e..5ea2d5d57d 100644 --- a/api/test/common/BUILD +++ b/api/test/common/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark") otel_cc_benchmark( diff --git a/api/test/common/CMakeLists.txt b/api/test/common/CMakeLists.txt index 330a7765aa..8d77dcdfab 100644 --- a/api/test/common/CMakeLists.txt +++ b/api/test/common/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + include(GoogleTest) foreach(testname kv_properties_test string_util_test) diff --git a/api/test/context/BUILD b/api/test/context/BUILD index f1a6ac163e..64b2cb750f 100644 --- a/api/test/context/BUILD +++ b/api/test/context/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark") cc_test( diff --git a/api/test/context/CMakeLists.txt b/api/test/context/CMakeLists.txt index e01e24eed0..25ce51bc20 100644 --- a/api/test/context/CMakeLists.txt +++ b/api/test/context/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + add_subdirectory(propagation) include(GoogleTest) diff --git a/api/test/context/propagation/BUILD b/api/test/context/propagation/BUILD index 388b5e0d36..d62d67649c 100644 --- a/api/test/context/propagation/BUILD +++ b/api/test/context/propagation/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark") cc_test( diff --git a/api/test/context/propagation/CMakeLists.txt b/api/test/context/propagation/CMakeLists.txt index 74a8176a2f..844aa123fa 100644 --- a/api/test/context/propagation/CMakeLists.txt +++ b/api/test/context/propagation/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + foreach(testname composite_propagator_test) add_executable(${testname} "${testname}.cc") target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} diff --git a/api/test/core/BUILD b/api/test/core/BUILD index 99fcfaecaf..38c65e6d31 100644 --- a/api/test/core/BUILD +++ b/api/test/core/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + cc_test( name = "timestamp_test", srcs = [ @@ -12,3 +15,18 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "version_test", + srcs = [ + "version_test.cc", + ], + tags = [ + "api", + "test", + ], + deps = [ + "//api", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/api/test/core/CMakeLists.txt b/api/test/core/CMakeLists.txt index 7fead491e5..7123f9a708 100644 --- a/api/test/core/CMakeLists.txt +++ b/api/test/core/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + include(GoogleTest) add_executable(timestamp_test timestamp_test.cc) @@ -7,3 +10,11 @@ gtest_add_tests( TARGET timestamp_test TEST_PREFIX trace. TEST_LIST timestamp_test) + +add_executable(version_test version_test.cc) +target_link_libraries(version_test ${GTEST_BOTH_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) +gtest_add_tests( + TARGET version_test + TEST_PREFIX version. + TEST_LIST version_test) diff --git a/api/test/core/version_test.cc b/api/test/core/version_test.cc new file mode 100644 index 0000000000..2e360ffdad --- /dev/null +++ b/api/test/core/version_test.cc @@ -0,0 +1,16 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/version.h" + +#include + +TEST(VersionTest, Consistency) +{ + char expected[10]; + snprintf(expected, sizeof(expected), "%d.%d.%d", OPENTELEMETRY_VERSION_MAJOR, + OPENTELEMETRY_VERSION_MINOR, OPENTELEMETRY_VERSION_PATCH); + + std::string actual = OPENTELEMETRY_VERSION; + EXPECT_EQ(actual, expected); +} diff --git a/api/test/logs/BUILD b/api/test/logs/BUILD index 34fda18db9..521620a209 100644 --- a/api/test/logs/BUILD +++ b/api/test/logs/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark") cc_test( diff --git a/api/test/logs/CMakeLists.txt b/api/test/logs/CMakeLists.txt index a5f9c04084..92d4c72450 100644 --- a/api/test/logs/CMakeLists.txt +++ b/api/test/logs/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + foreach(testname provider_test logger_test) add_executable(logs_api_${testname} "${testname}.cc") target_link_libraries(logs_api_${testname} ${GTEST_BOTH_LIBRARIES} diff --git a/api/test/logs/logger_test.cc b/api/test/logs/logger_test.cc index 48e9c375d3..d07e12e40e 100644 --- a/api/test/logs/logger_test.cc +++ b/api/test/logs/logger_test.cc @@ -5,6 +5,7 @@ # include # include +# include # include "opentelemetry/common/timestamp.h" # include "opentelemetry/logs/logger.h" @@ -27,7 +28,7 @@ TEST(Logger, GetLoggerDefault) { auto lp = Provider::GetLoggerProvider(); const std::string schema_url{"https://opentelemetry.io/schemas/1.11.0"}; - auto logger = lp->GetLogger("TestLogger", "", "opentelelemtry_library", "", schema_url); + auto logger = lp->GetLogger("TestLogger", "opentelelemtry_library", "", schema_url); auto name = logger->GetName(); EXPECT_NE(nullptr, logger); EXPECT_EQ(name, "noop logger"); @@ -38,65 +39,108 @@ TEST(Logger, GetNoopLoggerNameWithArgs) { auto lp = Provider::GetLoggerProvider(); - // GetLogger(name, list(args)) - std::array sv{"string"}; - span args{sv}; const std::string schema_url{"https://opentelemetry.io/schemas/1.11.0"}; - lp->GetLogger("NoopLoggerWithArgs", args, "opentelelemtry_library", "", schema_url); + lp->GetLogger("NoopLoggerWithArgs", "opentelelemtry_library", "", schema_url); - // GetLogger(name, string options) - lp->GetLogger("NoopLoggerWithOptions", "options", "opentelelemtry_library", "", schema_url); + lp->GetLogger("NoopLoggerWithOptions", "opentelelemtry_library", "", schema_url); } -// Test the Log() overloads +// Test the EmitLogRecord() overloads TEST(Logger, LogMethodOverloads) { auto lp = Provider::GetLoggerProvider(); const std::string schema_url{"https://opentelemetry.io/schemas/1.11.0"}; - auto logger = lp->GetLogger("TestLogger", "", "opentelelemtry_library", "", schema_url); + auto logger = lp->GetLogger("TestLogger", "opentelelemtry_library", "", schema_url); // Create a map to test the logs with std::map m = {{"key1", "value1"}}; - // Log overloads - logger->Log(Severity::kTrace, "Test log message"); - logger->Log(Severity::kInfo, "Test log message"); - logger->Log(Severity::kDebug, m); - logger->Log(Severity::kWarn, "Logging a map", m); - logger->Log(Severity::kError, {{"key1", "value 1"}, {"key2", 2}}); - logger->Log(Severity::kFatal, "Logging an initializer list", {{"key1", "value 1"}, {"key2", 2}}); + // EmitLogRecord overloads + logger->EmitLogRecord(Severity::kTrace, "Test log message"); + logger->EmitLogRecord(Severity::kInfo, "Test log message"); + logger->EmitLogRecord(Severity::kDebug, m); + logger->EmitLogRecord(Severity::kWarn, "Logging a map", m); + logger->EmitLogRecord(Severity::kError, + opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); + logger->EmitLogRecord(Severity::kFatal, "Logging an initializer list", + opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); + logger->EmitLogRecord(Severity::kDebug, opentelemetry::common::MakeAttributes(m)); + logger->EmitLogRecord(Severity::kDebug, + common::KeyValueIterableView>(m)); + std::pair array[] = {{"key1", "value1"}}; + logger->EmitLogRecord(Severity::kDebug, opentelemetry::common::MakeAttributes(array)); + std::vector> vec = {{"key1", "value1"}}; + logger->EmitLogRecord(Severity::kDebug, opentelemetry::common::MakeAttributes(vec)); // Severity methods logger->Trace("Test log message"); logger->Trace("Test log message", m); - logger->Trace("Test log message", {{"key1", "value 1"}, {"key2", 2}}); + logger->Trace("Test log message", + opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); logger->Trace(m); - logger->Trace({{"key1", "value 1"}, {"key2", 2}}); + logger->Trace(opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); logger->Debug("Test log message"); logger->Debug("Test log message", m); - logger->Debug("Test log message", {{"key1", "value 1"}, {"key2", 2}}); + logger->Debug("Test log message", + opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); logger->Debug(m); - logger->Debug({{"key1", "value 1"}, {"key2", 2}}); + logger->Debug(opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); logger->Info("Test log message"); logger->Info("Test log message", m); - logger->Info("Test log message", {{"key1", "value 1"}, {"key2", 2}}); + logger->Info("Test log message", + opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); logger->Info(m); - logger->Info({{"key1", "value 1"}, {"key2", 2}}); + logger->Info(opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); logger->Warn("Test log message"); logger->Warn("Test log message", m); - logger->Warn("Test log message", {{"key1", "value 1"}, {"key2", 2}}); + logger->Warn("Test log message", + opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); logger->Warn(m); - logger->Warn({{"key1", "value 1"}, {"key2", 2}}); + logger->Warn(opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); logger->Error("Test log message"); logger->Error("Test log message", m); - logger->Error("Test log message", {{"key1", "value 1"}, {"key2", 2}}); + logger->Error("Test log message", + opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); logger->Error(m); - logger->Error({{"key1", "value 1"}, {"key2", 2}}); + logger->Error(opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); logger->Fatal("Test log message"); logger->Fatal("Test log message", m); - logger->Fatal("Test log message", {{"key1", "value 1"}, {"key2", 2}}); + logger->Fatal("Test log message", + opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); logger->Fatal(m); - logger->Fatal({{"key1", "value 1"}, {"key2", 2}}); + logger->Fatal(opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); +} + +TEST(Logger, EventLogMethodOverloads) +{ + auto lp = Provider::GetLoggerProvider(); + const std::string schema_url{"https://opentelemetry.io/schemas/1.11.0"}; + auto logger = lp->GetLogger("TestLogger", "opentelelemtry_library", "", schema_url); + + auto elp = Provider::GetEventLoggerProvider(); + auto event_logger = elp->CreateEventLogger(logger, "otel-cpp.test"); + + std::map m = {{"key1", "value1"}}; + + event_logger->EmitEvent("event name", Severity::kTrace, "Test log message"); + event_logger->EmitEvent("event name", Severity::kInfo, "Test log message"); + event_logger->EmitEvent("event name", Severity::kDebug, m); + event_logger->EmitEvent("event name", Severity::kWarn, "Logging a map", m); + event_logger->EmitEvent( + "event name", Severity::kError, + opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); + event_logger->EmitEvent( + "event name", Severity::kFatal, "Logging an initializer list", + opentelemetry::common::MakeAttributes({{"key1", "value 1"}, {"key2", 2}})); + event_logger->EmitEvent("event name", Severity::kDebug, opentelemetry::common::MakeAttributes(m)); + event_logger->EmitEvent("event name", Severity::kDebug, + common::KeyValueIterableView>(m)); + std::pair array[] = {{"key1", "value1"}}; + event_logger->EmitEvent("event name", Severity::kDebug, + opentelemetry::common::MakeAttributes(array)); + std::vector> vec = {{"key1", "value1"}}; + event_logger->EmitEvent("event name", Severity::kDebug, + opentelemetry::common::MakeAttributes(vec)); } // Define a basic Logger class @@ -118,21 +162,13 @@ class TestLogger : public Logger class TestProvider : public LoggerProvider { nostd::shared_ptr 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 */) override - { - return shared_ptr(new TestLogger()); - } - - nostd::shared_ptr GetLogger(nostd::string_view /* logger_name */, - nostd::span /* args */, nostd::string_view /* library_name */, nostd::string_view /* library_version */, - nostd::string_view /* schema_url */) override + nostd::string_view /* schema_url */, + bool /* include_trace_context */, + const common::KeyValueIterable & /* attributes */) override { - return shared_ptr(new TestLogger()); + return nostd::shared_ptr(new TestLogger()); } }; @@ -146,7 +182,7 @@ TEST(Logger, PushLoggerImplementation) // Check that the implementation was pushed by calling TestLogger's GetName() nostd::string_view schema_url{"https://opentelemetry.io/schemas/1.11.0"}; - auto logger = lp->GetLogger("TestLogger", "", "opentelelemtry_library", "", schema_url); + auto logger = lp->GetLogger("TestLogger", "opentelelemtry_library", "", schema_url); ASSERT_EQ("test logger", logger->GetName()); } #endif diff --git a/api/test/logs/provider_test.cc b/api/test/logs/provider_test.cc index 1dd60d0b87..0d607f1d01 100644 --- a/api/test/logs/provider_test.cc +++ b/api/test/logs/provider_test.cc @@ -9,6 +9,8 @@ # include "opentelemetry/logs/provider.h" # include "opentelemetry/nostd/shared_ptr.h" +using opentelemetry::logs::EventLogger; +using opentelemetry::logs::EventLoggerProvider; using opentelemetry::logs::Logger; using opentelemetry::logs::LoggerProvider; using opentelemetry::logs::Provider; @@ -17,20 +19,13 @@ namespace nostd = opentelemetry::nostd; class TestProvider : public LoggerProvider { - nostd::shared_ptr 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 */) override - { - return shared_ptr(nullptr); - } - - nostd::shared_ptr GetLogger(nostd::string_view /* logger_name */, - nostd::span /* args */, - nostd::string_view /* library_name */, - nostd::string_view /* library_version */, - nostd::string_view /* schema_url */) override + nostd::shared_ptr GetLogger( + nostd::string_view /* logger_name */, + nostd::string_view /* library_name */, + nostd::string_view /* library_version */, + nostd::string_view /* schema_url */, + bool /* include_trace_context */, + const opentelemetry::common::KeyValueIterable & /* attributes */) override { return shared_ptr(nullptr); } @@ -64,14 +59,55 @@ TEST(Provider, GetLogger) auto tf = shared_ptr(new TestProvider()); // tests GetLogger(name, version, schema) const std::string schema_url{"https://opentelemetry.io/schemas/1.2.0"}; - auto logger = tf->GetLogger("logger1", "", "opentelelemtry_library", "", schema_url); + auto logger = tf->GetLogger("logger1", "opentelelemtry_library", "", schema_url); EXPECT_EQ(nullptr, logger); // tests GetLogger(name, arguments) - std::array sv{"string"}; - nostd::span args{sv}; - auto logger2 = tf->GetLogger("logger2", args, "opentelelemtry_library", "", schema_url); + auto logger2 = tf->GetLogger("logger2", "opentelelemtry_library", "", schema_url); EXPECT_EQ(nullptr, logger2); } + +class TestEventLoggerProvider : public EventLoggerProvider +{ +public: + nostd::shared_ptr CreateEventLogger( + nostd::shared_ptr /*delegate_logger*/, + nostd::string_view /*event_domain*/) noexcept override + { + return nostd::shared_ptr(nullptr); + } +}; + +TEST(Provider, GetEventLoggerProviderDefault) +{ + auto tf = Provider::GetEventLoggerProvider(); + EXPECT_NE(nullptr, tf); +} + +TEST(Provider, SetEventLoggerProvider) +{ + auto tf = nostd::shared_ptr(new TestEventLoggerProvider()); + Provider::SetEventLoggerProvider(tf); + ASSERT_EQ(tf, Provider::GetEventLoggerProvider()); +} + +TEST(Provider, MultipleEventLoggerProviders) +{ + auto tf = nostd::shared_ptr(new TestEventLoggerProvider()); + Provider::SetEventLoggerProvider(tf); + auto tf2 = nostd::shared_ptr(new TestEventLoggerProvider()); + Provider::SetEventLoggerProvider(tf2); + + ASSERT_NE(Provider::GetEventLoggerProvider(), tf); +} + +TEST(Provider, CreateEventLogger) +{ + auto tf = nostd::shared_ptr(new TestEventLoggerProvider()); + auto logger = tf->CreateEventLogger(nostd::shared_ptr(nullptr), "domain"); + + EXPECT_EQ(nullptr, logger); +} + #endif diff --git a/api/test/metrics/BUILD b/api/test/metrics/BUILD index d15d7511f4..86e20033b7 100644 --- a/api/test/metrics/BUILD +++ b/api/test/metrics/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark") cc_test( diff --git a/api/test/metrics/CMakeLists.txt b/api/test/metrics/CMakeLists.txt index 89ce81fd01..c63af9a7a9 100644 --- a/api/test/metrics/CMakeLists.txt +++ b/api/test/metrics/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + foreach(testname meter_provider_test noop_sync_instrument_test) add_executable(${testname} "${testname}.cc") target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} diff --git a/api/test/nostd/BUILD b/api/test/nostd/BUILD index 75166c5de5..4f2b1d31fd 100644 --- a/api/test/nostd/BUILD +++ b/api/test/nostd/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + cc_test( name = "function_ref_test", srcs = [ diff --git a/api/test/nostd/CMakeLists.txt b/api/test/nostd/CMakeLists.txt index dd783bf2d8..ee774261ea 100644 --- a/api/test/nostd/CMakeLists.txt +++ b/api/test/nostd/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + include(GoogleTest) foreach( diff --git a/api/test/nostd/span_test.cc b/api/test/nostd/span_test.cc index 09d32ecfb8..98e825142d 100644 --- a/api/test/nostd/span_test.cc +++ b/api/test/nostd/span_test.cc @@ -182,10 +182,10 @@ TEST(SpanTest, Iteration) std::array array = {1, 2, 3}; span s1{array.data(), array.size()}; - EXPECT_EQ(std::distance(s1.begin(), s1.end()), array.size()); + EXPECT_EQ(std::distance(s1.begin(), s1.end()), (ptrdiff_t)array.size()); EXPECT_TRUE(std::equal(s1.begin(), s1.end(), array.begin())); span s2{array.data(), array.size()}; - EXPECT_EQ(std::distance(s2.begin(), s2.end()), array.size()); + EXPECT_EQ(std::distance(s2.begin(), s2.end()), (ptrdiff_t)array.size()); EXPECT_TRUE(std::equal(s2.begin(), s2.end(), array.begin())); } diff --git a/api/test/plugin/BUILD b/api/test/plugin/BUILD index 98e3679b35..f20143ff77 100644 --- a/api/test/plugin/BUILD +++ b/api/test/plugin/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + cc_test( name = "dynamic_load_test", srcs = [ diff --git a/api/test/plugin/CMakeLists.txt b/api/test/plugin/CMakeLists.txt index 6bdcbf9c32..8930928f1e 100644 --- a/api/test/plugin/CMakeLists.txt +++ b/api/test/plugin/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + include(GoogleTest) add_executable(dynamic_load_test dynamic_load_test.cc) diff --git a/api/test/trace/BUILD b/api/test/trace/BUILD index 60d5c9f02c..d233084597 100644 --- a/api/test/trace/BUILD +++ b/api/test/trace/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark") cc_test( diff --git a/api/test/trace/CMakeLists.txt b/api/test/trace/CMakeLists.txt index 0e2d6631d3..34b49db84d 100644 --- a/api/test/trace/CMakeLists.txt +++ b/api/test/trace/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + add_subdirectory(propagation) foreach( diff --git a/api/test/trace/propagation/BUILD b/api/test/trace/propagation/BUILD index b21ba6bca3..8e9718e80f 100644 --- a/api/test/trace/propagation/BUILD +++ b/api/test/trace/propagation/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark") cc_test( diff --git a/api/test/trace/propagation/CMakeLists.txt b/api/test/trace/propagation/CMakeLists.txt index da60712c6d..e52957342a 100644 --- a/api/test/trace/propagation/CMakeLists.txt +++ b/api/test/trace/propagation/CMakeLists.txt @@ -1,5 +1,7 @@ -foreach(testname http_text_format_test b3_propagation_test - jaeger_propagation_test) +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +foreach(testname http_text_format_test b3_propagation_test) add_executable(${testname} "${testname}.cc") target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) @@ -8,3 +10,16 @@ foreach(testname http_text_format_test b3_propagation_test TEST_PREFIX trace. TEST_LIST ${testname}) endforeach() + +if(NOT WITH_NO_DEPRECATED_CODE) + foreach(testname jaeger_propagation_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 trace. + TEST_LIST ${testname}) + endforeach() +endif() diff --git a/bazel/BUILD b/bazel/BUILD index b7c95da5a5..2ea9008571 100644 --- a/bazel/BUILD +++ b/bazel/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + package(default_visibility = ["//:__subpackages__"]) config_setting( diff --git a/bazel/curl.BUILD b/bazel/curl.BUILD index 07e3ac12ff..f0418a62dd 100644 --- a/bazel/curl.BUILD +++ b/bazel/curl.BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + # Builds CURL from a distribution. load("@io_opentelemetry_cpp//bazel:curl.bzl", "CURL_COPTS") diff --git a/bazel/curl.bzl b/bazel/curl.bzl index 6a887c50c6..681fa1a856 100644 --- a/bazel/curl.bzl +++ b/bazel/curl.bzl @@ -1,16 +1,5 @@ -# 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. +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 # Compiler options for building libcurl. diff --git a/bazel/nlohmann_json.BUILD b/bazel/nlohmann_json.BUILD index cd2d93eef6..df45444c0b 100644 --- a/bazel/nlohmann_json.BUILD +++ b/bazel/nlohmann_json.BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + licenses(["notice"]) # 3-Clause BSD exports_files(["LICENSE.MIT"]) diff --git a/bazel/opentelemetry_proto.BUILD b/bazel/opentelemetry_proto.BUILD index eb5981f186..88cc56fdfa 100644 --- a/bazel/opentelemetry_proto.BUILD +++ b/bazel/opentelemetry_proto.BUILD @@ -1,16 +1,5 @@ -# 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. +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 package(default_visibility = ["//visibility:public"]) diff --git a/bazel/otel_cc_benchmark.bzl b/bazel/otel_cc_benchmark.bzl index c40681917f..61e9fe8d69 100644 --- a/bazel/otel_cc_benchmark.bzl +++ b/bazel/otel_cc_benchmark.bzl @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + def otel_cc_benchmark(name, srcs, deps, tags = [""]): """ Creates targets for the benchmark and related targets. diff --git a/bazel/repository.bzl b/bazel/repository.bzl index 210ee20258..e03e48ae5a 100644 --- a/bazel/repository.bzl +++ b/bazel/repository.bzl @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") @@ -119,10 +122,10 @@ def opentelemetry_cpp_deps(): maybe( http_archive, name = "com_github_jupp0r_prometheus_cpp", - sha256 = "07018db604ea3e61f5078583e87c80932ea10c300d979061490ee1b7dc8e3a41", - strip_prefix = "prometheus-cpp-1.0.0", + sha256 = "397544fe91e183029120b4eebcfab24ed9ec833d15850aae78fd5db19062d13a", + strip_prefix = "prometheus-cpp-1.1.0", urls = [ - "https://github.com/jupp0r/prometheus-cpp/archive/refs/tags/v1.0.0.tar.gz", + "https://github.com/jupp0r/prometheus-cpp/archive/refs/tags/v1.1.0.tar.gz", ], ) @@ -179,6 +182,17 @@ def opentelemetry_cpp_deps(): ], ) + # Opentracing + maybe( + http_archive, + name = "com_github_opentracing", + sha256 = "5b170042da4d1c4c231df6594da120875429d5231e9baa5179822ee8d1054ac3", + strip_prefix = "opentracing-cpp-1.6.0", + urls = [ + "https://github.com/opentracing/opentracing-cpp/archive/refs/tags/v1.6.0.tar.gz", + ], + ) + # boost headers from vcpkg maybe( native.new_local_repository, diff --git a/buildscripts/pre-commit b/buildscripts/pre-commit index ce83da51be..eb09e01c2c 100755 --- a/buildscripts/pre-commit +++ b/buildscripts/pre-commit @@ -43,11 +43,17 @@ short_version="${major}.${minor}.${patch}" full_version="${short_version}-${pre_release}-${build_metadata}-${count_new_commits}-${branch}-${latest_commit_hash}" # Update api version.h -sed -i "/^\#define OPENTELEMETRY_VERSION/c\#define OPENTELEMETRY_VERSION \"${short_version}\"" "$(pwd)/api/include/opentelemetry/version.h" +sed -i "/^\#define OPENTELEMETRY_VERSION /c\#define OPENTELEMETRY_VERSION \"${short_version}\"" "$(pwd)/api/include/opentelemetry/version.h" +sed -i "/^\#define OPENTELEMETRY_VERSION_MAJOR /c\#define OPENTELEMETRY_VERSION_MAJOR ${major}" "$(pwd)/api/include/opentelemetry/version.h" +sed -i "/^\#define OPENTELEMETRY_VERSION_MINOR /c\#define OPENTELEMETRY_VERSION_MINOR ${minor}" "$(pwd)/api/include/opentelemetry/version.h" +sed -i "/^\#define OPENTELEMETRY_VERSION_PATCH /c\#define OPENTELEMETRY_VERSION_PATCH ${patch}" "$(pwd)/api/include/opentelemetry/version.h" git add "$(pwd)/api/include/opentelemetry/version.h" # Update sdk version.cc cat > "$(pwd)/sdk/src/version/version.cc" < /dev/null exit 0 elif [[ "$1" == "bazel.tsan" ]]; then - bazel $BAZEL_STARTUP_OPTIONS test --config=tsan $BAZEL_TEST_OPTIONS_ASYNC //... - bazel $BAZEL_STARTUP_OPTIONS run --config=tsan $BAZEL_TEST_OPTIONS_ASYNC \ - //examples/metrics_simple:metrics_ostream_example > /dev/null +# TODO - potential race condition in Civetweb server used by prometheus-cpp during shutdown +# https://github.com/civetweb/civetweb/issues/861, so removing prometheus from the test + bazel $BAZEL_STARTUP_OPTIONS test --config=tsan $BAZEL_TEST_OPTIONS_ASYNC -- //... -//exporters/prometheus/... exit 0 elif [[ "$1" == "bazel.valgrind" ]]; then bazel $BAZEL_STARTUP_OPTIONS build $BAZEL_OPTIONS_ASYNC //... diff --git a/ci/docfx.cmd b/ci/docfx.cmd index 46582ac980..a2dd80cabd 100644 --- a/ci/docfx.cmd +++ b/ci/docfx.cmd @@ -1,3 +1,6 @@ +REM Copyright The OpenTelemetry Authors +REM SPDX-License-Identifier: Apache-2.0 + SETLOCAL ENABLEEXTENSIONS type ci\docfx.json > docfx.json diff --git a/ci/install_protobuf.sh b/ci/install_protobuf.sh index 8fff91d062..dde94111e1 100755 --- a/ci/install_protobuf.sh +++ b/ci/install_protobuf.sh @@ -5,12 +5,38 @@ set -e -[ -z "${PROTOBUF_VERSION}" ] && export PROTOBUF_VERSION="3.11.4" +[ -z "${PROTOBUF_VERSION}" ] && export PROTOBUF_VERSION="21.12" + +# +# Note +# +# protobuf uses two release number schemes, +# for example 3.21.12 and 21.12, +# and both tags corresponds to the same commit: +# +# commit f0dc78d7e6e331b8c6bb2d5283e06aa26883ca7c (HEAD -> release-3.21.12, tag: v3.21.12, tag: v21.12) +# Author: Protobuf Team Bot +# Date: Mon Dec 12 16:03:12 2022 -0800 +# +# Updating version.json and repo version numbers to: 21.12 +# +# tag v21.12 corresponds to the 'protoc version', or repo version +# tag v3.21.12 corresponds to the 'cpp version' +# +# protobuf-cpp-3.21.12.tar.gz: +# - is provided under releases/download/v21.12 +# - is no longer provided under releases/download/v3.21.12, +# +# Use the "repo version number" (PROTOBUF_VERSION=21.12) +# when calling this script +# + +export CPP_PROTOBUF_VERSION="3.${PROTOBUF_VERSION}" cd / -wget https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protobuf-cpp-${PROTOBUF_VERSION}.tar.gz -tar zxf protobuf-cpp-${PROTOBUF_VERSION}.tar.gz --no-same-owner -cd protobuf-${PROTOBUF_VERSION} +wget https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protobuf-cpp-${CPP_PROTOBUF_VERSION}.tar.gz +tar zxf protobuf-cpp-${CPP_PROTOBUF_VERSION}.tar.gz --no-same-owner +cd protobuf-${CPP_PROTOBUF_VERSION} ./configure -make && make install +make -j $(nproc) && make install ldconfig diff --git a/ci/install_windows_bazelisk.ps1 b/ci/install_windows_bazelisk.ps1 index de70bba6fc..4867882afe 100644 --- a/ci/install_windows_bazelisk.ps1 +++ b/ci/install_windows_bazelisk.ps1 @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + $ErrorActionPreference = "Stop" trap { $host.SetShouldExit(1) } diff --git a/ci/install_windows_protobuf.ps1 b/ci/install_windows_protobuf.ps1 index 4e1b1b8f05..0faea9f5eb 100644 --- a/ci/install_windows_protobuf.ps1 +++ b/ci/install_windows_protobuf.ps1 @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + $ErrorActionPreference = "Stop" trap { $host.SetShouldExit(1) } diff --git a/ci/ports/benchmark/portfile.cmake b/ci/ports/benchmark/portfile.cmake index 2b889dc9ce..6716c34312 100644 --- a/ci/ports/benchmark/portfile.cmake +++ b/ci/ports/benchmark/portfile.cmake @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + if(VCPKG_CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") message(FATAL_ERROR "${PORT} does not currently support UWP") endif() diff --git a/ci/ports/protobuf/portfile.cmake b/ci/ports/protobuf/portfile.cmake index 77b718e5fd..12c7e95fdc 100644 --- a/ci/ports/protobuf/portfile.cmake +++ b/ci/ports/protobuf/portfile.cmake @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + vcpkg_from_github( OUT_SOURCE_PATH SOURCE_PATH REPO protocolbuffers/protobuf diff --git a/ci/setup_thrift.ps1 b/ci/setup_thrift.ps1 index a9be25262d..52cd96708a 100644 --- a/ci/setup_thrift.ps1 +++ b/ci/setup_thrift.ps1 @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + $ErrorActionPreference = "Stop" trap { $host.SetShouldExit(1) } @@ -10,4 +13,4 @@ setx VCPKG_DIR "$VCPKG_DIR" # boost needed for thrift ./vcpkg "--vcpkg-root=$VCPKG_DIR" install boost-predef[core]:x64-windows boost-locale[core]:x64-windows boost-numeric-conversion[core]:x64-windows boost-scope-exit[core]:x64-windows openssl:x64-windows -Pop-Location \ No newline at end of file +Pop-Location diff --git a/ci/setup_thrift.sh b/ci/setup_thrift.sh index 98e14d5e71..1c8897089f 100755 --- a/ci/setup_thrift.sh +++ b/ci/setup_thrift.sh @@ -1,5 +1,8 @@ #!/bin/bash +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + set -e export DEBIAN_FRONTEND=noninteractive export THRIFT_VERSION=0.14.1 diff --git a/ci/setup_windows_ci_environment.ps1 b/ci/setup_windows_ci_environment.ps1 index 4a0e04459d..6d003bd0ef 100755 --- a/ci/setup_windows_ci_environment.ps1 +++ b/ci/setup_windows_ci_environment.ps1 @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + $ErrorActionPreference = "Stop" trap { $host.SetShouldExit(1) } diff --git a/ci/setup_windows_cmake.ps1 b/ci/setup_windows_cmake.ps1 index 3248b4c722..172b126aaa 100755 --- a/ci/setup_windows_cmake.ps1 +++ b/ci/setup_windows_cmake.ps1 @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + $ErrorActionPreference = "Stop" trap { $host.SetShouldExit(1) } diff --git a/cmake/ParseOsRelease.cmake b/cmake/ParseOsRelease.cmake index 6aadf48d52..26c6109dc2 100644 --- a/cmake/ParseOsRelease.cmake +++ b/cmake/ParseOsRelease.cmake @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + # Parse /etc/os-release to determine Linux distro if(EXISTS /etc/os-release) @@ -19,4 +22,4 @@ else() set("OS_RELEASE_NAME" ${CMAKE_SYSTEM_NAME}) set("OS_RELEASE_ID" ${CMAKE_SYSTEM_NAME}) set("OS_RELEASE_VERSION_ID" "1.0") -endif() \ No newline at end of file +endif() diff --git a/cmake/modules/FindThrift.cmake b/cmake/modules/FindThrift.cmake index c7baf07f0e..563e2c44d0 100644 --- a/cmake/modules/FindThrift.cmake +++ b/cmake/modules/FindThrift.cmake @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + # This module defines Thrift_LIBRARIES, libraries to link Thrift_INCLUDE_DIR, # Thrift_FOUND, If false, do not try to use it. diff --git a/cmake/nlohmann-json.cmake b/cmake/nlohmann-json.cmake index b5b4355e45..84f107b97c 100644 --- a/cmake/nlohmann-json.cmake +++ b/cmake/nlohmann-json.cmake @@ -1,42 +1,91 @@ -if("${nlohmann-json}" STREQUAL "") +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +# +# The dependency on nlohmann_json can be provided different ways. By order of +# decreasing priority, options are: +# +# 1 - Search for a nlohmann_json package +# +# Packages installed on the local machine are used if found. +# +# The nlohmann_json dependency is not installed, as it already is. +# +# 2 - Search for a nlohmann_json git submodule +# +# When git submodule is used, the nlohmann_json code is located in: +# third_party/nlohmann-json +# +# The nlohmann_json dependency is installed, by building the sub directory with +# JSON_Install=ON +# +# 3 - Download nlohmann_json from github +# +# Code from the development branch is used, unless a specific release tag is +# provided in variable ${nlohmann-json} +# +# The nlohmann_json dependency is installed, by building the downloaded code +# with JSON_Install=ON +# + +# nlohmann_json package is required for most SDK build configurations +find_package(nlohmann_json QUIET) +set(nlohmann_json_clone FALSE) +if(nlohmann_json_FOUND) + message(STATUS "nlohmann::json dependency satisfied by: package") +elseif(EXISTS ${PROJECT_SOURCE_DIR}/.git + AND EXISTS + ${PROJECT_SOURCE_DIR}/third_party/nlohmann-json/CMakeLists.txt) + message(STATUS "nlohmann::json dependency satisfied by: git submodule") + set(JSON_BuildTests + OFF + CACHE INTERNAL "") + set(JSON_Install + ON + CACHE INTERNAL "") + # This option allows to link nlohmann_json::nlohmann_json target + add_subdirectory(${PROJECT_SOURCE_DIR}/third_party/nlohmann-json) + # This option allows to add header to include directories + include_directories( + ${PROJECT_SOURCE_DIR}/third_party/nlohmann-json/single_include) +else() + if("${nlohmann-json}" STREQUAL "") set(nlohmann-json "develop") -endif() -include(ExternalProject) -ExternalProject_Add(nlohmann_json_download + endif() + message(STATUS "nlohmann::json dependency satisfied by: github download") + set(nlohmann_json_clone TRUE) + include(ExternalProject) + ExternalProject_Add( + nlohmann_json_download PREFIX third_party GIT_REPOSITORY https://github.com/nlohmann/json.git - GIT_TAG - "${nlohmann-json}" + GIT_TAG "${nlohmann-json}" UPDATE_COMMAND "" - CMAKE_ARGS - -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} - -DJSON_BuildTests=OFF - -DJSON_Install=ON - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} - TEST_AFTER_INSTALL - 0 - DOWNLOAD_NO_PROGRESS - 1 - LOG_CONFIGURE - 1 - LOG_BUILD - 1 - LOG_INSTALL - 1 -) + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} + -DJSON_BuildTests=OFF -DJSON_Install=ON + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + TEST_AFTER_INSTALL 0 + DOWNLOAD_NO_PROGRESS 1 + LOG_CONFIGURE 1 + LOG_BUILD 1 + LOG_INSTALL 1) -ExternalProject_Get_Property(nlohmann_json_download INSTALL_DIR) -SET(NLOHMANN_JSON_INCLUDE_DIR ${INSTALL_DIR}/src/nlohmann_json_download/single_include) -add_library(nlohmann_json_ INTERFACE) -target_include_directories(nlohmann_json_ INTERFACE - "$" - "$") -add_dependencies(nlohmann_json_ nlohmann_json_download) -add_library(nlohmann_json::nlohmann_json ALIAS nlohmann_json_) + ExternalProject_Get_Property(nlohmann_json_download INSTALL_DIR) + set(NLOHMANN_JSON_INCLUDE_DIR + ${INSTALL_DIR}/src/nlohmann_json_download/single_include) + add_library(nlohmann_json_ INTERFACE) + target_include_directories( + nlohmann_json_ INTERFACE "$" + "$") + add_dependencies(nlohmann_json_ nlohmann_json_download) + add_library(nlohmann_json::nlohmann_json ALIAS nlohmann_json_) -install( - TARGETS nlohmann_json_ - EXPORT "${PROJECT_NAME}-target" - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + if(OPENTELEMETRY_INSTALL) + install( + TARGETS nlohmann_json_ + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif() +endif() diff --git a/cmake/opentelemetry-cpp-config.cmake.in b/cmake/opentelemetry-cpp-config.cmake.in index b6dcd5e276..adae58dd1b 100644 --- a/cmake/opentelemetry-cpp-config.cmake.in +++ b/cmake/opentelemetry-cpp-config.cmake.in @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + #.rst: # opentelemetry-cpp-config.cmake # -------- @@ -46,13 +49,12 @@ # opentelemetry-cpp::jaeger_trace_exporter - Imported target of opentelemetry-cpp::jaeger_trace_exporter # opentelemetry-cpp::zpages - Imported target of opentelemetry-cpp::zpages # opentelemetry-cpp::http_client_curl - Imported target of opentelemetry-cpp::http_client_curl +# opentelemetry-cpp::opentracing_shim - Imported target of opentelemetry-cpp::opentracing_shim # # ============================================================================= -# Copyright 2020 opentelemetry. -# -# Distributed under the Apache License (the "License"); see accompanying file -# LICENSE for details. +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 # ============================================================================= set(OPENTELEMETRY_ABI_VERSION_NO @@ -101,7 +103,8 @@ set(_OPENTELEMETRY_CPP_LIBRARIES_TEST_TARGETS etw_exporter jaeger_trace_exporter zpages - http_client_curl) + http_client_curl + opentracing_shim) foreach(_TEST_TARGET IN LISTS _OPENTELEMETRY_CPP_LIBRARIES_TEST_TARGETS) if(TARGET opentelemetry-cpp::${_TEST_TARGET}) list(APPEND OPENTELEMETRY_CPP_LIBRARIES opentelemetry-cpp::${_TEST_TARGET}) diff --git a/cmake/opentelemetry-proto.cmake b/cmake/opentelemetry-proto.cmake index a21c0f16cf..1aa1ba0349 100644 --- a/cmake/opentelemetry-proto.cmake +++ b/cmake/opentelemetry-proto.cmake @@ -2,32 +2,33 @@ # SPDX-License-Identifier: Apache-2.0 # -# The dependency on opentelemetry-proto can be provided different ways. -# By order of decreasing priority, options are: +# The dependency on opentelemetry-proto can be provided different ways. By order +# of decreasing priority, options are: # # 1 - Use a provided package # # This is useful to build opentelemetry-cpp as part of a super project. # -# The super project provides the path to the opentelemetry-proto -# source code using variable ${OTELCPP_PROTO_PATH} +# The super project provides the path to the opentelemetry-proto source code +# using variable ${OTELCPP_PROTO_PATH} # # 2 - Search for a opentelemetry-proto git submodule # -# When git submodule is used, -# the opentelemetry-proto code is located in: +# When git submodule is used, the opentelemetry-proto code is located in: # third_party/opentelemetry-proto # # 3 - Download opentelemetry-proto from github # -# Code from the required version is used, -# unless a specific release tag is provided -# in variable ${opentelemetry-proto} +# Code from the required version is used, unless a specific release tag is +# provided in variable ${opentelemetry-proto} # if(OTELCPP_PROTO_PATH) - if(NOT EXISTS "${OTELCPP_PROTO_PATH}/opentelemetry/proto/common/v1/common.proto") - message(FATAL_ERROR "OTELCPP_PROTO_PATH does not point to a opentelemetry-proto repository") + if(NOT EXISTS + "${OTELCPP_PROTO_PATH}/opentelemetry/proto/common/v1/common.proto") + message( + FATAL_ERROR + "OTELCPP_PROTO_PATH does not point to a opentelemetry-proto repository") endif() message(STATUS "opentelemetry-proto dependency satisfied by: external path") set(PROTO_PATH ${OTELCPP_PROTO_PATH}) @@ -35,10 +36,12 @@ if(OTELCPP_PROTO_PATH) else() if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/third_party/opentelemetry-proto/.git) message(STATUS "opentelemetry-proto dependency satisfied by: git submodule") - set(PROTO_PATH "${CMAKE_CURRENT_SOURCE_DIR}/third_party/opentelemetry-proto") + set(PROTO_PATH + "${CMAKE_CURRENT_SOURCE_DIR}/third_party/opentelemetry-proto") set(needs_proto_download FALSE) else() - message(STATUS "opentelemetry-proto dependency satisfied by: github download") + message( + STATUS "opentelemetry-proto dependency satisfied by: github download") if("${opentelemetry-proto}" STREQUAL "") set(opentelemetry-proto "v0.19.0") endif() @@ -259,18 +262,20 @@ endif() set_target_properties(opentelemetry_proto PROPERTIES EXPORT_NAME proto) patch_protobuf_targets(opentelemetry_proto) -install( - TARGETS opentelemetry_proto - EXPORT "${PROJECT_NAME}-target" - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +if(OPENTELEMETRY_INSTALL) + install( + TARGETS opentelemetry_proto + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) -install( - DIRECTORY ${GENERATED_PROTOBUF_PATH}/opentelemetry - DESTINATION include - FILES_MATCHING - PATTERN "*.h") + install( + DIRECTORY ${GENERATED_PROTOBUF_PATH}/opentelemetry + DESTINATION include + FILES_MATCHING + PATTERN "*.h") +endif() if(TARGET protobuf::libprotobuf) target_link_libraries(opentelemetry_proto PUBLIC protobuf::libprotobuf) diff --git a/cmake/package.cmake b/cmake/package.cmake index eeba8068f9..ef0a879e0f 100644 --- a/cmake/package.cmake +++ b/cmake/package.cmake @@ -1,3 +1,5 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 set(CPACK_PACKAGE_DESCRIPTION "OpenTelemetry C++ for Linux") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "OpenTelemetry C++ for Linux - C++ Implementation of OpenTelemetry Specification") @@ -54,7 +56,7 @@ elseif(WIN32) find_program(NUGETCAPABLE nuget) if(NOT NUGETCAPABLE MATCHES "NOTFOUND") set(CPACK_NUGET_PACKAGE_NAME "${CPACK_PROJECT_NAME}") - set(CPACK_NUGET_PACKAGE_VERSION "${OPENTELEMETRY_VERSIOM}") + set(CPACK_NUGET_PACKAGE_VERSION "${OPENTELEMETRY_VERSION}") set(CPACK_NUGET_PACKAGE_DESCRIPTION "${CPACK_PACKAGE_DESCRIPTION}") set(CPACK_NUGET_PACKAGE_AUTHORS "${CPACK_PACKAGE_VENDOR}") set(CPACK_NUGET_PACKAGE_TITLE "${CPACK_PACKAGE_DESCRIPTION_SUMMARY}") diff --git a/cmake/proto-options-patch.cmake b/cmake/proto-options-patch.cmake index ed294ea793..97872050c9 100644 --- a/cmake/proto-options-patch.cmake +++ b/cmake/proto-options-patch.cmake @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + macro(check_append_cxx_compiler_flag OUTPUT_VAR) foreach(CHECK_FLAG ${ARGN}) check_cxx_compiler_flag(${CHECK_FLAG} diff --git a/docker/Dockerfile b/docker/Dockerfile index 118cac62f9..412f997747 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + ARG BASE_IMAGE=ubuntu:latest ARG GRPC_IMAGE=grpc-${BASE_IMAGE} ARG THRIFT_IMAGE=thrift-${BASE_IMAGE} diff --git a/docker/Dockerfile.alpine.base b/docker/Dockerfile.alpine.base index 2595efa70f..0a92f26af5 100644 --- a/docker/Dockerfile.alpine.base +++ b/docker/Dockerfile.alpine.base @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + ARG BASE_IMAGE=alpine:latest ARG CORES=${nproc} diff --git a/docker/Dockerfile.centos b/docker/Dockerfile.centos index 66138ba60a..c95595691b 100644 --- a/docker/Dockerfile.centos +++ b/docker/Dockerfile.centos @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + FROM centos:7 ARG TOOLSET_VER=11 diff --git a/docker/Dockerfile.debian.deps b/docker/Dockerfile.debian.deps index 0634c11970..9ee7e9519b 100644 --- a/docker/Dockerfile.debian.deps +++ b/docker/Dockerfile.debian.deps @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + ARG BASE_IMAGE=ubuntu:latest ARG CORES=${nproc} diff --git a/docker/grpc/CMakeLists.txt b/docker/grpc/CMakeLists.txt index 8cb69cc6c3..7254da1dcc 100644 --- a/docker/grpc/CMakeLists.txt +++ b/docker/grpc/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + cmake_minimum_required(VERSION 3.11 FATAL_ERROR) project( diff --git a/docker/grpc/Dockerfile b/docker/grpc/Dockerfile index fee3082b2d..2d88d209b6 100644 --- a/docker/grpc/Dockerfile +++ b/docker/grpc/Dockerfile @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + ARG BASE_IMAGE=ubuntu:latest FROM ${BASE_IMAGE} AS grpc diff --git a/docker/thrift/CMakeLists.txt b/docker/thrift/CMakeLists.txt index 0028dc48c7..aa94362986 100644 --- a/docker/thrift/CMakeLists.txt +++ b/docker/thrift/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + cmake_minimum_required(VERSION 3.11 FATAL_ERROR) project( diff --git a/docker/thrift/Dockerfile b/docker/thrift/Dockerfile index 2c57199f3f..60792e597b 100644 --- a/docker/thrift/Dockerfile +++ b/docker/thrift/Dockerfile @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + ARG BASE_IMAGE=ubuntu:latest FROM ${BASE_IMAGE} AS thrift diff --git a/docker/ubuntuLatest/Dockerfile b/docker/ubuntuLatest/Dockerfile index 6a1a88388a..5e13a7d3b8 100644 --- a/docker/ubuntuLatest/Dockerfile +++ b/docker/ubuntuLatest/Dockerfile @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + FROM ubuntu:latest ENV DEBIAN_FRONTEND=noninteractive WORKDIR /work diff --git a/docs/build-as-dll.md b/docs/build-as-dll.md new file mode 100644 index 0000000000..9a53639834 --- /dev/null +++ b/docs/build-as-dll.md @@ -0,0 +1,11 @@ +# Design of building OpenTelemetry C++ SDK and exporters as DLL + +**NOTE**: the current build produces a single DLL which includes API, SDK and +exporters. This **MAY** change in future. + +OpenTelemetry C++ can be built into single DLL named opentelemetry_cpp.dll on +Windows, with CMake flag `OPENTELEMETRY_BUILD_DLL` set to `ON`. + +To instrument an application based on the DLL, please define macro +`OPENTELEMETRY_BUILD_IMPORT_DLL` before including any OpenTelemetry API header +files in the application source files. diff --git a/docs/dependencies.md b/docs/dependencies.md index 7094eeae52..06c3806d34 100644 --- a/docs/dependencies.md +++ b/docs/dependencies.md @@ -46,7 +46,7 @@ Both these dependencies are listed here: - OTLP messages are constructed as protobuf payloads. - `protoc` compiler is used to generate C++ stubs for proto files provided by `opentelemetry-proto`. - - `libprotobuf` library is used for generating serialised trace/metrics/log + - `libprotobuf` library is used for generating serialized trace/metrics/log data to be sent to opentelemetry collector. - License: The library is licensed [here](https://github.com/protocolbuffers/protobuf/blob/master/LICENSE). @@ -80,7 +80,7 @@ Both these dependencies are listed here: - [Thrift](https://github.com/apache/thrift) - Serialization and RPC framework. - `thrift` compiler to generate C++ stubs for IDL data model for Jaeger. - - `libthrift` library to generate serialised trace/metrics/log data to be + - `libthrift` library to generate serialized trace/metrics/log data to be sent to remote Jaeger service. Note: libthrift **0.12.0** doesn't work with this Jaeger exporter. See [#1680](https://github.com/open-telemetry/opentelemetry-cpp/issues/1680). @@ -104,3 +104,10 @@ Both these dependencies are listed here: - [Zpages](/ext/src/zpages): - None + +- [Opentracing](/opentracing-shim) + shim: + - [`opentracing-cpp`](https://github.com/opentracing/opentracing-cpp) + OpenTracing API for C++ + - A bridge layer implementing the OpenTracing API using the OpenTelemetry API + - License: `Apache License 2.0` diff --git a/docs/deprecation-process.md b/docs/deprecation-process.md new file mode 100644 index 0000000000..81d3e845ce --- /dev/null +++ b/docs/deprecation-process.md @@ -0,0 +1,433 @@ +# Deprecation process + +## Motivation + +Deprecation of code is a difficult topic, +which can become a point of friction. + +On one hand, maintainers have to maintain the code base +for many platforms, many compilers, while making bug fixes +and adding new features over time. + +To do so, sometime code cleanup, minor refactoring, or removal of +previous engineering debt is required to maintain a healthy code base, +to allow for further improvements. + +In short, maintainers may want to, or may have to, +remove some apis during the lifetime of a project. + +On the other hand, users who have a working application built using +opentelemetry-cpp, for a given platform, a given compiler, and a given +configuration, prefer to have stability and as few changes as possible. + +Doing code changes in the application imply a new build / test / deploy +cycle, which induce costs, and risks. + +In short, users typically do now want changes, if the code works for them. + +The following extreme behaviors are what needs to be avoided for a project +to stay healthy: + +* constant changes in the code base, done without notice, + introducing incompatibilities, causing adoption of each new release to + be costly with code rewrite. While this allows maintainers to make + more releases, it ultimately slows down adoption from users. + +* impossibility to make any changes in the code base, or having to support + many different flavors of the same api for compatibility reasons, + which introduces cost, technical risks, and code bloat, ultimately slowing + innovation down. + +The whole idea of a deprecation and removal process is to provide some +mitigation, that will satisfy both maintainers and users, while allowing +both to move forward with their own areas or responsibilities. + +Also, note that some areas of the code are considered stable, while others +are maturing (feature preview), or experimental and in active development. + +The deprecation and removal process is primarily for stable parts of the +code. Code in feature preview and experimental is expected to change in a +faster pace, possibly with short of no notice in case of experimental code. + +This process attempts to provide: + +* visibility on the delivery pipeline itself, so that deprecations are + visible and documented in advance, +* sufficient time between the deprecation and the removal of an API, + so that users can adapt the application at a time of their choice, + planned, instead of having to do it in emergency, +* tooling to verify if a given code base is exposed to deprecated code or + not, to help assess how much effort is required to stay up to date, +* migration and mitigations, to document not only that some api is going + away, but to also provide instructions to adjust the code with an + alternate solution. + +## Artifacts + +### Issues + +Deprecation issues should be tagged with the "Deprecated" label, +for example like +[issue #1892](https://github.com/open-telemetry/opentelemetry-cpp/issues/1892). + +Removal issues should be tagged with the "Removal" label, +for example like +[issue #1938](https://github.com/open-telemetry/opentelemetry-cpp/issues/1938). + +Discoverability of ongoing deprecations and removals is the key here, +to avoid surprises. + +### The DEPRECATED document + +At any given time, file `DEPRECATED` lists all the ongoing deprecations, +no matter how long ago these were announced. + +A user using release N should find, when reading `DEPRECATED`, +if a given api was deprecated in release N-5 or N-10, without having to go back to +release notes from past versions. + +When a removal is finally implemented, the `DEPRECATED` file is expunged, +so it contains only the currently active deprecations. + +Main sections in that document are organized as follows: + +* [Platforms] +* [Compilers] +* [Third party dependencies] +* [Build tools] + * This is for `CMake`, `Bazel`, `Doxygen`, ... + * Changes of tooling go here. +* [Build scripts] + * This is for `CMakeLists.txt`, `BUILD`, `Doxyfile`, ... + * Changes of build options go here. +* [opentelemetry-cpp API] +* [opentelemetry-cpp SDK] +* [opentelemetry-cpp Exporter] +* [Documentation] + +Please keep main sections as is, with a content of "N/A", instead of +removing sections with no current deprecations. + +## Workflow + +### Decide deprecation + +The first step is to discuss, typically in SIG C++ meeting, +the need to deprecate a given feature or api. + +Upon agreement, +file an issue in GitHub so it becomes visible to all parties +following closely development. + +Use [DEPRECATION] in the title, and tag with label "Deprecation". + +For highly visible features, +consider other ways to improve awareness, such as: + +* pin the deprecation issue in the GitHub UI, +* discussions in the slack channels +* discussions with other teams in open-telemetry +* blog posts + +### Prepare deprecation + +Implement the deprecation issue with a PR. + +Deprecation consist of two parts, communication and tooling. + +For the communication, the PR should add an entry in file `DEPRECATED`, +detailing the following sections: + +* Announcement + * set `Version:` to TO-BE-RELEASED-VERSION + * set `Date:` to TO-BE-RELEASED-DATE + * set `PR:` to the deprecation PR + * If applicable, add references to any other relevant document + (slack discussion, blog, meeting minutes) +* Motivation + * add justifications for the need to deprecate. + * this step is critical to get support from users that will be affected, + instead of getting push back. +* Scope: + * details which part are affected. + * when applicable, give the exact name of CMake options, + C++ header files, classes, functions, etc, + so that users can easily search in their code base + for references to the deprecated items, + and assess the exposure to deprecated code. +* Mitigation: + * indicate any tooling available to identify the + deprecated code still in use, + * indicate technical mitigations if known, + * name replacement apis, libraries, compiling options, etc, + and describe how to adjust the user code in general, + to remove any dependencies on deprecated code. +* Planned removal: + * Indicate an estimated date and/or version, if known, + by which the deprecated code will be removed, + * this allows users to plan accordingly, to minimize disruption. + +For the tooling, the PR should implement any code change necessary +to help users transition to a clean code base, +where all dependencies to deprecated code are removed. + +This imply these dependencies can be identified, +in a reliable way. + +The goal is to, at the same time: + +* not break existing functionality in any way, in "normal" mode, +* find all references to deprecated code, in "verify" mode. + +See [Technical guidelines](#technical-guidelines) for examples. + +Once both parts are addressed, +get the PR reviewed and merged to the main branch. + +File a different issue, to remove the deprecated code later. + +Use [REMOVAL] in the title, and tag with label "Removal". + +In the removal issue, refer to the corresponding deprecation issue. + +### Release deprecation + +When making a new opentelemetry-cpp release, +in addition to the regular release tasks: + +* Replace every occurrences of `TO-BE-RELEASED-VERSION` in file + `DEPRECATED` with the new release version, +* Replace every occurrences of `TO-BE-RELEASED-DATE` in file + `DEPRECATED` with the new release date, +* In the `CHANGELOG` and the release notes, add references + to the new deprecated items for this release, + pointing to the `DEPRECATED` document. + +### Wait + +Do not implement the removal right away. + +First, if a removal is implemented and merged to main just after a new release, +it exposes itself to a full revert, should another release be necessary to fix +any regressions just caused recently. + +Second, some people will only notice the deprecation when discovering it +in the release, no matter how many previous announcements were done. +Allow some time for people to raise issues or concerns, +especially if there are special usage patterns that were not anticipated. + +Once things are stable, proceed with the removal. +Depending on the change, it can be implemented: + +* in the next minor release, +* after a few minor releases, +* in the next major release, +* after a few major releases + +following the deprecation. + +The more disruptive the change is, +the more time users will need to adjust, +so trivial deprecations can be removed right away, +while complex ones can take much longer. + +In any case, never implement the deprecation and the removal in the same +release: wait. + +### Prepare removal + +Implement the removal issue with a PR. + +Remove all the deprecated code. + +Remove all the tooling (compiling options) related to the deprecated code, +if any. + +Remove all the relevant entries in `DEPRECATED`. + +Add a `CHANGELOG` entry for the removal. + +Get the removal PR reviewed and merged to the main branch. + +### Release removal + +When making a new opentelemetry-cpp release, +in addition to the regular release tasks: + +* In the `CHANGELOG` and the release notes, add references + to the new removed items for this release. + +## Technical guidelines + +### CMake options deprecation + +Assume the option `WITH_FOO` needs to be deprecated. + +Code using `WITH_FOO=OFF` or `WITH_FOO=ON` must build as before, +yet users should be notified if they use `WITH_FOO` in their build. + +CMake defines a `WITH_NO_DEPRECATED_CODE` option, set to OFF by default. + +In a normal build, used in production, code is compiled with +`WITH_NO_DEPRECATED_CODE=OFF`. + +In a verification build, code is compiled with `WITH_NO_DEPRECATED_CODE=ON`. +This verification also defines `OPENTELEMETRY_NO_DEPRECATED_CODE`, for code +level checks. + +Implement the following logic in CMake: + +```cmake + option(WITH_FOO "DEPRECATED - With the foo feature" OFF) + + if(WITH_FOO) + if(WITH_NO_DEPRECATED_CODE) + message(FATAL_ERROR "WITH_FOO is deprecated") + else() + message(WARNING "WITH_FOO is deprecated") + endif() + endif +``` + +The verification build is not meant to be used in production. +It is meant to find all references of deprecated items. + +If the verification build succeeds, the user code is guaranteed to be clean, +and will not be impacted by the removal to come. + +When implementing such logic, document it in the mitigation section, +in file `DEPRECATED`. + +### C++ deprecation + +#### C++ header deprecation + +When a header is deprecated, it will be removed, +so users should no longer include the header. + +Add the following code in the header file + +```cpp +#ifdef OPENTELEMETRY_NO_DEPRECATED_CODE +# error "header is deprecated." +#endif +``` + +#### macro deprecation + +For macros, there are no `[[deprecated]]` annotations. + +Replace the macro with something that is sure to fail at build time, +so it gets noticed when used. + +```cpp +#ifndef OPENTELEMETRY_NO_DEPRECATED_CODE + #define OTEL_MACRO_FOO(X, Y) ... (normal implementation) ... +#else + #define OTEL_MACRO_FOO(X, Y) { this macro foo is deprecated } +#endif + +``` + +#### C++ code deprecation + +Assume a C++ item needs to be deprecated. + +For example: + +```cpp + struct some_options + { + int x; + int y; // TODO: deprecate me + int z; + }; +``` + +Code using y must build as before, and yet users should be notified if still +using y. + +First, there is a way in C++ to flag deprecated code: + +```cpp + struct some_options + { + int x; + OPENTELEMETRY_DEPRECATED int y; // deprecated, to be removed + int z; + }; +``` + +This will cause deprecation warnings. +Some users will notice, but others will not, +because warnings are most of the time ignored. + +A better solution is to provide a way to forcefully +remove the deprecated code: + +```cpp + struct some_options + { + int x; +#ifndef OPENTELEMETRY_NO_DEPRECATED_CODE + OPENTELEMETRY_DEPRECATED int y; // deprecated, to be removed +#endif + int z; + }; +``` + +A regular build, to use in production, will build with +the regular, unchanged, configuration, +in which OPENTELEMETRY_NO_DEPRECATED_CODE is not defined. + +A verification build, to _not_ use in production, +will build with `OPENTELEMETRY_NO_DEPRECATED_CODE` defined, +removing the deprecated member entirely. + +A verification build that succeeds is a proof that +the application does not use the deprecated member, +and needs no change. + +A verification build that fails will list all the application code that needs +to be fixed before the deprecated code is finally removed. + +Even if the verification build succeeds, it really should not be used in +production, because the memory layout just changed, breaking the ABI. + +This verification build is used to enforce: + +* the API (Application _Programming_ Interface) subset is compatible, + aka the source code will build before and after the removal. + +By the time the removal is implemented: + +```cpp + struct some_options + { + int x; + int z; + }; +``` + +the new release will have: + +* a reduced API +* an ABI (Application _Binary_ Interface) change + +The reduced API will be: + +* a subset of the original API, +* compatible with applications which no longer use the removed code +* incompatible with applications which still uses the removed code + +When documenting the deprecation, document this logic in the mitigation +section, so that users know how to find and remove old references to +deprecated code. + +When documenting the removal, clarify in the release notes that the +release is API compatible (when application cleanup was done), +but not ABI compatible (when sizeof() or virtual tables of classes changed), +and therefore a full build must be done again. + +This example used a member in a struct, but the same applies to other +constructs as well (classes, structs, functions, methods, etc). diff --git a/docs/library-distribution.md b/docs/library-distribution.md index 3fcbce4739..00794f87a0 100644 --- a/docs/library-distribution.md +++ b/docs/library-distribution.md @@ -118,7 +118,7 @@ Examples: NGINX's dynamic module capability, tracing can be supported as a plugin. For instance, the [nginx-opentracing module](https://github.com/opentracing-contrib/nginx-opentracing) provides - this type of extension and is used by projects such as Kubernete's [ingress + this type of extension and is used by projects such as Kubernetes [ingress controller](https://kubernetes.github.io/ingress-nginx/user-guide/third-party-addons/opentracing/). * The CPython binary also has no knowledge of OpenTelemetry, but C++ Python extension modules can be instrumented for OpenTelemetry. diff --git a/docs/public/Makefile b/docs/public/Makefile index 042a0ebb70..85085abef1 100644 --- a/docs/public/Makefile +++ b/docs/public/Makefile @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + # Minimal makefile for Sphinx documentation # diff --git a/docs/public/conf.py b/docs/public/conf.py index 26a407f73c..5a1390fe99 100644 --- a/docs/public/conf.py +++ b/docs/public/conf.py @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + # Configuration file for the Sphinx documentation builder. # # This file only contains a selection of the most common options. For a full @@ -21,7 +24,7 @@ author = 'OpenTelemetry authors' # The full version, including alpha/beta/rc tags -release = "1.8.1" +release = "1.9.0" # Run sphinx on subprojects and copy output # ----------------------------------------- diff --git a/docs/testing-with-ssl.md b/docs/testing-with-ssl.md new file mode 100644 index 0000000000..47fdfeab64 --- /dev/null +++ b/docs/testing-with-ssl.md @@ -0,0 +1,351 @@ +# Testing with SSL/TLS + +## Required software + +The opentelemetry-collector +[documentation](https://opentelemetry.io/docs/collector/configuration/#setting-up-certificates) +uses [cfssl](https://github.com/cloudflare/cfssl), +so we are using cfssl as well here. + +In addition, install `openssl`, which provides tooling for testing. + +## Generating CERT + +### Generating CA CERT + +First, write a CA request file in json, named `ca_csr.json` + +It should contains the following data: + +```console +shell> cat ca_csr.json +{ + "hosts": ["localhost", "127.0.0.1"], + "key": { + "algo": "rsa", + "size": 2048 + }, + "names": [ + { + "O": "OpenTelemetry CA Example" + } + ] +} +``` + +Then, generate a CA certificate: + +```console +shell> cfssl genkey -initca ca_csr.json | cfssljson -bare ca +2022/12/13 16:42:57 [INFO] generate received request +2022/12/13 16:42:57 [INFO] received CSR +2022/12/13 16:42:57 [INFO] generating key: rsa-2048 +2022/12/13 16:42:57 [INFO] encoded CSR +2022/12/13 16:42:57 [INFO] signed certificate with serial number 78705522450145914781445058194934247010984259280 +``` + +This will create three files, `ca.csr`, `ca.pem` and `ca-key.pem` + +Congratulation, "OpenTelemetry CA Example" is now a CA certification +authority, with signing keys. + +### Generating Client CERT + +Second, write a certificate request file in json, named `client_csr.json`, +for the opentelemetry-cpp client. + +It should contains the following data: + +```console +shell> cat client_csr.json +{ + "hosts": ["localhost", "127.0.0.1"], + "key": { + "algo": "rsa", + "size": 2048 + }, + "names": [ + { + "O": "OpenTelemetry Client Example" + } + ] +} +``` + +Note that the name ("OpenTelemetry Client Example") should be different +from the CA authority name ("OpenTelemetry CA Example"), +otherwise the client certificate will be self-signed, and rejected later in SSL/TLS. + +Now, use the CA certificate generated in the previous step +to create and sign a new client certificate. + +```console +shell> cfssl gencert -ca ca.pem -ca-key ca-key.pem client_csr.json | cfssljson -bare client_cert +2022/12/13 16:50:18 [INFO] generate received request +2022/12/13 16:50:18 [INFO] received CSR +2022/12/13 16:50:18 [INFO] generating key: rsa-2048 +2022/12/13 16:50:18 [INFO] encoded CSR +2022/12/13 16:50:18 [INFO] signed certificate with serial number 579932794730090029542135367576037344135399122179 +``` + +This will create three files, `client_cert.csr`, `client_cert.pem` and `client_cert-key.pem` + +### Generating Server CERT + +Third and likewise, write a certificate request file in json, named `server_csr.json`, +for the opentelemetry server (the opentelemetry-collector) + +It should contains the following data: + +```console +shell> cat server_csr.json +{ + "hosts": ["localhost", "127.0.0.1"], + "key": { + "algo": "rsa", + "size": 2048 + }, + "names": [ + { + "O": "OpenTelemetry Server Example" + } + ] +} +``` + +Likewise, use a different name from the CA authority name. + +Use the CA certificate to create and sign a new server certificate. + +```console +shell> cfssl gencert -ca ca.pem -ca-key ca-key.pem server_csr.json | cfssljson -bare server_cert +2022/12/13 17:04:40 [INFO] generate received request +2022/12/13 17:04:40 [INFO] received CSR +2022/12/13 17:04:40 [INFO] generating key: rsa-2048 +2022/12/13 17:04:40 [INFO] encoded CSR +2022/12/13 17:04:40 [INFO] signed certificate with serial number 332420451189450993545238745169293824985460186638 +``` + +This will create three files, `server_cert.csr`, `server_cert.pem` and `server_cert-key.pem` + +### Verify certificates + +Verify the certificates generated, using `openssl`: + +```console +shell> openssl verify -CAfile ca.pem server_cert.pem client_cert.pem +server_cert.pem: OK +client_cert.pem: OK +``` + +Useful commands, to inspect certificates if needed (output not shown here) + +```console +shell> openssl x509 -in ca.pem -text +``` + +```console +shell> openssl x509 -in client_cert.pem -text +``` + +```console +shell> openssl x509 -in server_cert.pem -text +``` + +## OpenTelemetry SSL clients + +### Simulated client, for testing + +Use `openssl` to simulate an opentelemetry-cpp client connecting to port 4318: + +```console +shell> openssl s_client -connect localhost:4318 -CAfile ca.pem -cert client_cert.pem -key client_cert-key.pem +``` + +### OTLP HTTP Client + +Use the example `example_otlp_http` client to connect to an OTLP HTTP server: + +```console +shell> export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://localhost:4318/v1/traces +shell> export OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE=ca.pem +shell> export OTEL_EXPORTER_OTLP_TRACES_CLIENT_CERTIFICATE=client_cert.pem +shell> export OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY=client_cert-key.pem +shell> example_otlp_http +``` + +## OpenTelemetry SSL servers + +### Simulated server, for testing + +Use `openssl` to simulate an opentelemetry-collector process serving port 4318: + +```console +shell> openssl s_server -accept 4318 -CAfile ca.pem -cert server_cert.pem -key server_cert-key.pem +Using default temp DH parameters +ACCEPT +``` + +This command does not return, +the server waits for SSL connections (Use CTRL-C to quit). + +### OTLP HTTP Server + +To use a server that: + +- implements OTLP HTTP +- supports SSL + +use the opentelemetry-collector, +configured to use SSL/TLS for receivers: + +```console +shell> cat otel-collector-config-ssl.yaml +receivers: + otlp: + protocols: + http: + tls: + ca_file: ca.pem + cert_file: server_cert.pem + key_file: server_cert-key.pem +... +``` + +For example: + +```console +shell> /path/to/bin/otelcorecol_linux_amd64 --config /path/to/otel-config-ssl.yaml +``` + +Note, the `example/http/http_example` can not be used (it understands neither SSL +nor OTLP HTTP). + +## Testing SSL on the wire + +### Fake client with fake server + +This configuration tests nothing in opentelemetry, +but is useful to understand what a nominal SSL communication between a +client and a server should look like. + +### Real client with fake server + +In this configuration, we can test that the opentelemetry-cpp +client actually sends SSL traffic on the wire. + +### Fake client with real server + +In this configuration, we can test that the opentelemetry-collector +server actually accepts SSL traffic on the wire. +This can be used to verify the client keys are working properly. + +## Full integration test with SSL + +Start an opentelemetry-collector, configured to use SSL/TLS. + +```console +shell> /path/to/bin/otelcorecol_linux_amd64 --config /path/to/otel-config-ssl.yaml +... +2022-12-13T18:03:21.140+0100 info otlpreceiver@v0.66.0/otlp.go:89 Starting HTTP server {"kind": "receiver", "name": "otlp", "pipeline": "metrics", "endpoint": "0.0.0.0:4318"} +2022-12-13T18:03:21.141+0100 info service/pipelines.go:106 Receiver started. {"kind": "receiver", "name": "otlp", "pipeline": "metrics"} +2022-12-13T18:03:21.141+0100 info service/pipelines.go:102 Receiver is starting... {"kind": "receiver", "name": "otlp", "pipeline": "traces"} +2022-12-13T18:03:21.141+0100 info service/pipelines.go:106 Receiver started. {"kind": "receiver", "name": "otlp", "pipeline": "traces"} +2022-12-13T18:03:21.141+0100 info service/service.go:105 Everything is ready. Begin running and processing data. +``` + +Start the example_otlp_http client, configured to use SSL/TLS. + +```console +shell> export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://localhost:4318/v1/traces +shell> export OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE=ca.pem +shell> export OTEL_EXPORTER_OTLP_TRACES_CLIENT_CERTIFICATE=client_cert.pem +shell> export OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY=client_cert-key.pem +shell> example_otlp_http +``` + +The opentelemetry-collector process receives data, as seen in logs: + +```console +2022-12-13T18:05:36.611+0100 info TracesExporter {"kind": "exporter", "data_type": "traces", "name": "logging", "#spans": 4} +2022-12-13T18:05:36.611+0100 info ResourceSpans #0 +Resource SchemaURL: +Resource attributes: + -> service.name: Str(unknown_service) + -> telemetry.sdk.version: Str(1.8.1) + -> telemetry.sdk.name: Str(opentelemetry) + -> telemetry.sdk.language: Str(cpp) +ScopeSpans #0 +ScopeSpans SchemaURL: +InstrumentationScope foo_library 1.8.1 +Span #0 + Trace ID : ebbd7e13e9cdfb05f0ca9ed4b0cdf6c0 + Parent ID : 042ae76539c294c6 + ID : c87b21d63c505bae + Name : f1 + Kind : Internal + Start time : 2022-12-13 17:05:36.482165738 +0000 UTC + End time : 2022-12-13 17:05:36.482170938 +0000 UTC + Status code : Unset + Status message : +ResourceSpans #1 +Resource SchemaURL: +Resource attributes: + -> service.name: Str(unknown_service) + -> telemetry.sdk.version: Str(1.8.1) + -> telemetry.sdk.name: Str(opentelemetry) + -> telemetry.sdk.language: Str(cpp) +ScopeSpans #0 +ScopeSpans SchemaURL: +InstrumentationScope foo_library 1.8.1 +Span #0 + Trace ID : ebbd7e13e9cdfb05f0ca9ed4b0cdf6c0 + Parent ID : 042ae76539c294c6 + ID : 801227b9ee6d3b03 + Name : f1 + Kind : Internal + Start time : 2022-12-13 17:05:36.487636362 +0000 UTC + End time : 2022-12-13 17:05:36.487641983 +0000 UTC + Status code : Unset + Status message : +ResourceSpans #2 +Resource SchemaURL: +Resource attributes: + -> service.name: Str(unknown_service) + -> telemetry.sdk.version: Str(1.8.1) + -> telemetry.sdk.name: Str(opentelemetry) + -> telemetry.sdk.language: Str(cpp) +ScopeSpans #0 +ScopeSpans SchemaURL: +InstrumentationScope foo_library 1.8.1 +Span #0 + Trace ID : ebbd7e13e9cdfb05f0ca9ed4b0cdf6c0 + Parent ID : 6489f2ada8d95da0 + ID : 042ae76539c294c6 + Name : f2 + Kind : Internal + Start time : 2022-12-13 17:05:36.482154908 +0000 UTC + End time : 2022-12-13 17:05:36.488641122 +0000 UTC + Status code : Unset + Status message : +ResourceSpans #3 +Resource SchemaURL: +Resource attributes: + -> service.name: Str(unknown_service) + -> telemetry.sdk.version: Str(1.8.1) + -> telemetry.sdk.name: Str(opentelemetry) + -> telemetry.sdk.language: Str(cpp) +ScopeSpans #0 +ScopeSpans SchemaURL: +InstrumentationScope foo_library 1.8.1 +Span #0 + Trace ID : ebbd7e13e9cdfb05f0ca9ed4b0cdf6c0 + Parent ID : + ID : 6489f2ada8d95da0 + Name : library + Kind : Internal + Start time : 2022-12-13 17:05:36.482136052 +0000 UTC + End time : 2022-12-13 17:05:36.489263125 +0000 UTC + Status code : Unset + Status message : +``` diff --git a/docs/using-clang-format.md b/docs/using-clang-format.md index 24d2404763..3d1fcc108f 100644 --- a/docs/using-clang-format.md +++ b/docs/using-clang-format.md @@ -48,6 +48,6 @@ For further guidance on editor integration, see these specific pages: No. For the project as a whole, using clang-format is just one optional way to format your code. While it will produce style-guide conformant code, other -formattings would also satisfy the style guide. For certain modules it may be +formats would also satisfy the style guide. For certain modules it may be appropriate to use alternate coding style. In those scenarios a local directory *.clang-format* settings file takes precedence over the one at top-level. diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 1f891f412d..7ffec0fab4 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + add_subdirectory(common) include_directories(common) if(WITH_OTLP_GRPC OR WITH_OTLP_HTTP) @@ -18,10 +21,16 @@ endif() if(WITH_PROMETHEUS) add_subdirectory(prometheus) endif() +if(WITH_LOGS_PREVIEW) + add_subdirectory(logs_simple) +endif() add_subdirectory(plugin) add_subdirectory(simple) add_subdirectory(batch) add_subdirectory(metrics_simple) add_subdirectory(multithreaded) add_subdirectory(multi_processor) -add_subdirectory(http) + +if(WITH_EXAMPLES_HTTP) + add_subdirectory(http) +endif() diff --git a/examples/batch/BUILD b/examples/batch/BUILD index 2dedf6b29e..c5db0f4b65 100644 --- a/examples/batch/BUILD +++ b/examples/batch/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + cc_binary( name = "example_simple", srcs = [ diff --git a/examples/batch/CMakeLists.txt b/examples/batch/CMakeLists.txt index d1146d59b3..126a8c068b 100644 --- a/examples/batch/CMakeLists.txt +++ b/examples/batch/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + include_directories(${CMAKE_SOURCE_DIR}/exporters/ostream/include) add_executable(batch_span_processor_example main.cc) diff --git a/examples/batch/main.cc b/examples/batch/main.cc index 2793694d49..a417933247 100644 --- a/examples/batch/main.cc +++ b/examples/batch/main.cc @@ -19,7 +19,7 @@ namespace nostd = opentelemetry::nostd; namespace { -void initTracer() +void InitTracer() { auto exporter = trace_exporter::OStreamSpanExporterFactory::Create(); @@ -46,6 +46,12 @@ void initTracer() trace_api::Provider::SetTracerProvider(provider); } +void CleanupTracer() +{ + std::shared_ptr none; + trace_api::Provider::SetTracerProvider(none); +} + nostd::shared_ptr get_tracer() { auto provider = trace_api::Provider::GetTracerProvider(); @@ -65,7 +71,7 @@ void StartAndEndSpans() int main() { // Removing this line will leave the default noop TracerProvider in place. - initTracer(); + InitTracer(); std::cout << "Creating first batch of " << kNumSpans << " spans and waiting 3 seconds ...\n"; StartAndEndSpans(); @@ -83,7 +89,9 @@ int main() StartAndEndSpans(); printf("Shutting down and draining queue.... \n"); std::this_thread::sleep_for(std::chrono::milliseconds(2000)); - // We immediately let the program terminate which invokes the processor destructor + + // We invoke the processor destructor // which in turn invokes the processor Shutdown(), which finally drains the queue of ALL // its spans. + CleanupTracer(); } diff --git a/examples/common/CMakeLists.txt b/examples/common/CMakeLists.txt index c2fdca2594..f1e02f8e2d 100644 --- a/examples/common/CMakeLists.txt +++ b/examples/common/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + add_subdirectory(foo_library) if(WITH_LOGS_PREVIEW) add_subdirectory(logs_foo_library) diff --git a/examples/common/foo_library/BUILD b/examples/common/foo_library/BUILD index beffe5ca10..541d78692b 100644 --- a/examples/common/foo_library/BUILD +++ b/examples/common/foo_library/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + package(default_visibility = ["//visibility:public"]) cc_library( diff --git a/examples/common/foo_library/CMakeLists.txt b/examples/common/foo_library/CMakeLists.txt index a13512ffeb..cceb200596 100644 --- a/examples/common/foo_library/CMakeLists.txt +++ b/examples/common/foo_library/CMakeLists.txt @@ -1,3 +1,10 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +if(DEFINED OPENTELEMETRY_BUILD_DLL) + add_definitions(-DOPENTELEMETRY_BUILD_IMPORT_DLL) +endif() + add_library(common_foo_library foo_library.h foo_library.cc) target_link_libraries(common_foo_library PUBLIC ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) diff --git a/examples/common/logs_foo_library/BUILD b/examples/common/logs_foo_library/BUILD index 956c7a5697..3dc0ae9fba 100644 --- a/examples/common/logs_foo_library/BUILD +++ b/examples/common/logs_foo_library/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + package(default_visibility = ["//visibility:public"]) cc_library( diff --git a/examples/common/logs_foo_library/CMakeLists.txt b/examples/common/logs_foo_library/CMakeLists.txt index df14f5c98b..45fe112f4e 100644 --- a/examples/common/logs_foo_library/CMakeLists.txt +++ b/examples/common/logs_foo_library/CMakeLists.txt @@ -1,3 +1,10 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +if(DEFINED OPENTELEMETRY_BUILD_DLL) + add_definitions(-DOPENTELEMETRY_BUILD_IMPORT_DLL) +endif() + add_library(common_logs_foo_library foo_library.h foo_library.cc) target_link_libraries(common_logs_foo_library PUBLIC ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) diff --git a/examples/common/logs_foo_library/foo_library.cc b/examples/common/logs_foo_library/foo_library.cc index 9e41584067..e952220108 100644 --- a/examples/common/logs_foo_library/foo_library.cc +++ b/examples/common/logs_foo_library/foo_library.cc @@ -22,7 +22,7 @@ nostd::shared_ptr get_tracer() nostd::shared_ptr get_logger() { auto provider = logs::Provider::GetLoggerProvider(); - return provider->GetLogger("foo_library_logger", "", "foo_library"); + return provider->GetLogger("foo_library_logger", "foo_library"); } } // namespace @@ -32,8 +32,8 @@ void foo_library() auto scoped_span = trace::Scope(get_tracer()->StartSpan("foo_library")); auto ctx = span->GetContext(); auto logger = get_logger(); - logger->Log(opentelemetry::logs::Severity::kDebug, "body", {}, ctx.trace_id(), ctx.span_id(), - ctx.trace_flags(), - opentelemetry::common::SystemTimestamp(std::chrono::system_clock::now())); + logger->EmitLogRecord(opentelemetry::logs::Severity::kDebug, "body", ctx.trace_id(), + ctx.span_id(), ctx.trace_flags(), + opentelemetry::common::SystemTimestamp(std::chrono::system_clock::now())); } #endif diff --git a/examples/common/metrics_foo_library/BUILD b/examples/common/metrics_foo_library/BUILD index bc84949732..55ab0154d8 100644 --- a/examples/common/metrics_foo_library/BUILD +++ b/examples/common/metrics_foo_library/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + package(default_visibility = ["//visibility:public"]) cc_library( diff --git a/examples/common/metrics_foo_library/CMakeLists.txt b/examples/common/metrics_foo_library/CMakeLists.txt index 4f2bca2a0b..e4f73fe037 100644 --- a/examples/common/metrics_foo_library/CMakeLists.txt +++ b/examples/common/metrics_foo_library/CMakeLists.txt @@ -1,2 +1,5 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + add_library(common_metrics_foo_library foo_library.h foo_library.cc) target_link_libraries(common_metrics_foo_library PUBLIC opentelemetry_api) diff --git a/examples/etw_threads/CMakeLists.txt b/examples/etw_threads/CMakeLists.txt index fd6ac76443..008e4518de 100644 --- a/examples/etw_threads/CMakeLists.txt +++ b/examples/etw_threads/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + project(etw_threadpool) add_executable(etw_threadpool main.cc) diff --git a/examples/grpc/BUILD b/examples/grpc/BUILD index 4b2de49cb1..b1d04e9fbd 100644 --- a/examples/grpc/BUILD +++ b/examples/grpc/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + package(default_visibility = ["//visibility:public"]) load("@rules_proto//proto:defs.bzl", "proto_library") diff --git a/examples/grpc/CMakeLists.txt b/examples/grpc/CMakeLists.txt index 4b701999e9..1ea1c9bee5 100644 --- a/examples/grpc/CMakeLists.txt +++ b/examples/grpc/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + # Proto file get_filename_component(proto_file "./protos/messages.proto" ABSOLUTE) get_filename_component(proto_file_path "${proto_file}" PATH) diff --git a/examples/grpc/README.md b/examples/grpc/README.md index 96d1dc2797..0b72963233 100644 --- a/examples/grpc/README.md +++ b/examples/grpc/README.md @@ -24,7 +24,7 @@ of tracing such as: ``find_package(gRPC)`` -2. Build and Deploy the opentelementry-cpp as described in +2. Build and Deploy the opentelemetry-cpp as described in [INSTALL.md](../../INSTALL.md). Building the project will build all of the examples and create new folders containing their executables within the 'build' directory NOT the 'examples' directory. diff --git a/examples/grpc/client.cc b/examples/grpc/client.cc index f47dfa3a4b..11fde192b3 100644 --- a/examples/grpc/client.cc +++ b/examples/grpc/client.cc @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + // Make sure to include GRPC headers first because otherwise Abseil may create // ambiguity with `nostd::variant` if compiled with Visual Studio 2015. Other // modern compilers are unaffected. @@ -98,7 +101,7 @@ void RunClient(uint16_t port) int main(int argc, char **argv) { - initTracer(); + InitTracer(); // set global propagator context::propagation::GlobalTextMapPropagator::SetGlobalPropagator( opentelemetry::nostd::shared_ptr( @@ -114,5 +117,6 @@ int main(int argc, char **argv) port = default_port; } RunClient(port); + CleanupTracer(); return 0; } diff --git a/examples/grpc/protos/messages.proto b/examples/grpc/protos/messages.proto index e0d69959bf..ccab03cd68 100644 --- a/examples/grpc/protos/messages.proto +++ b/examples/grpc/protos/messages.proto @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + syntax = "proto3"; package grpc_example; diff --git a/examples/grpc/server.cc b/examples/grpc/server.cc index a38fe802d7..6ba96a009e 100644 --- a/examples/grpc/server.cc +++ b/examples/grpc/server.cc @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + #ifdef BAZEL_BUILD # include "examples/grpc/protos/messages.grpc.pb.h" #else @@ -107,7 +110,7 @@ void RunServer(uint16_t port) int main(int argc, char **argv) { - initTracer(); + InitTracer(); constexpr uint16_t default_port = 8800; uint16_t port; if (argc > 1) @@ -120,5 +123,6 @@ int main(int argc, char **argv) } RunServer(port); + CleanupTracer(); return 0; } diff --git a/examples/grpc/tracer_common.h b/examples/grpc/tracer_common.h index 71f0afeaa7..073bffd50a 100644 --- a/examples/grpc/tracer_common.h +++ b/examples/grpc/tracer_common.h @@ -69,7 +69,7 @@ class GrpcServerCarrier : public opentelemetry::context::propagation::TextMapCar ServerContext *context_; }; -void initTracer() +void InitTracer() { auto exporter = opentelemetry::exporter::trace::OStreamSpanExporterFactory::Create(); auto processor = @@ -90,6 +90,12 @@ void initTracer() new opentelemetry::trace::propagation::HttpTraceContext())); } +void CleanupTracer() +{ + std::shared_ptr none; + opentelemetry::trace::Provider::SetTracerProvider(none); +} + opentelemetry::nostd::shared_ptr get_tracer(std::string tracer_name) { auto provider = opentelemetry::trace::Provider::GetTracerProvider(); diff --git a/examples/http/BUILD b/examples/http/BUILD index ac36bc0cee..6e98ac03f5 100644 --- a/examples/http/BUILD +++ b/examples/http/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + cc_binary( name = "example_http_client", srcs = [ diff --git a/examples/http/CMakeLists.txt b/examples/http/CMakeLists.txt index a1181c93a4..3aeb2624a1 100644 --- a/examples/http/CMakeLists.txt +++ b/examples/http/CMakeLists.txt @@ -1,20 +1,17 @@ -find_package(CURL) +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 -if(NOT CURL_FOUND) - message(WARNING "Skipping http client/server example build: CURL not found") -else() - include_directories(${CMAKE_SOURCE_DIR}/exporters/ostream/include - ${CMAKE_SOURCE_DIR}/ext/include ${CMAKE_SOURCE_DIR/}) +include_directories(${CMAKE_SOURCE_DIR}/exporters/ostream/include + ${CMAKE_SOURCE_DIR}/ext/include ${CMAKE_SOURCE_DIR/}) - add_executable(http_client client.cc) - add_executable(http_server server.cc) +add_executable(http_client client.cc) +add_executable(http_server server.cc) - target_link_libraries( - http_client ${CMAKE_THREAD_LIBS_INIT} opentelemetry_trace - opentelemetry_http_client_curl opentelemetry_exporter_ostream_span - ${CURL_LIBRARIES}) +target_link_libraries( + http_client ${CMAKE_THREAD_LIBS_INIT} opentelemetry_trace + opentelemetry_http_client_curl opentelemetry_exporter_ostream_span + ${CURL_LIBRARIES}) - target_link_libraries( - http_server ${CMAKE_THREAD_LIBS_INIT} opentelemetry_trace - opentelemetry_http_client_curl opentelemetry_exporter_ostream_span) -endif() +target_link_libraries( + http_server ${CMAKE_THREAD_LIBS_INIT} opentelemetry_trace + opentelemetry_http_client_curl opentelemetry_exporter_ostream_span) diff --git a/examples/http/README.md b/examples/http/README.md index 70285170fc..a02acbe898 100644 --- a/examples/http/README.md +++ b/examples/http/README.md @@ -21,7 +21,7 @@ to server. The example shows several aspects of tracing such as: * [HTTP Server](https://github.com/open-telemetry/opentelemetry-cpp/tree/main/ext/include/opentelemetry/ext/http/server) -2. Build and Deploy the opentelementry-cpp as described in +2. Build and Deploy the opentelemetry-cpp as described in [INSTALL.md](../../INSTALL.md) 3. Start the server from the `examples/http` directory diff --git a/examples/http/client.cc b/examples/http/client.cc index 9525b297e1..46be83bf2e 100644 --- a/examples/http/client.cc +++ b/examples/http/client.cc @@ -39,7 +39,7 @@ void sendRequest(const std::string &url) prop->Inject(carrier, current_ctx); // send http request - http_client::Result result = http_client->Get(url, carrier.headers_); + http_client::Result result = http_client->GetNoSsl(url, carrier.headers_); if (result) { // set span attributes @@ -73,7 +73,7 @@ void sendRequest(const std::string &url) int main(int argc, char *argv[]) { - initTracer(); + InitTracer(); constexpr char default_host[] = "localhost"; constexpr char default_path[] = "/helloworld"; constexpr uint16_t default_port = 8800; @@ -82,7 +82,7 @@ int main(int argc, char *argv[]) // The port the validation service listens to can be specified via the command line. if (argc > 1) { - port = atoi(argv[1]); + port = (uint16_t)(atoi(argv[1])); } else { @@ -92,4 +92,5 @@ int main(int argc, char *argv[]) std::string url = "http://" + std::string(default_host) + ":" + std::to_string(port) + std::string(default_path); sendRequest(url); + CleanupTracer(); } diff --git a/examples/http/server.cc b/examples/http/server.cc index 87a95500db..13f250684e 100644 --- a/examples/http/server.cc +++ b/examples/http/server.cc @@ -70,12 +70,12 @@ class RequestHandler : public HTTP_SERVER_NS::HttpRequestCallback int main(int argc, char *argv[]) { - initTracer(); + InitTracer(); // The port the validation service listens to can be specified via the command line. if (argc > 1) { - server_port = atoi(argv[1]); + server_port = (uint16_t)atoi(argv[1]); } HttpServer http_server(server_name, server_port); @@ -91,5 +91,6 @@ int main(int argc, char *argv[]) } http_server.Stop(); root_span->End(); + CleanupTracer(); return 0; } diff --git a/examples/http/tracer_common.h b/examples/http/tracer_common.h index 6402442d97..0b74d2ff8e 100644 --- a/examples/http/tracer_common.h +++ b/examples/http/tracer_common.h @@ -59,7 +59,7 @@ class HttpTextMapCarrier : public opentelemetry::context::propagation::TextMapCa T headers_; }; -void initTracer() +void InitTracer() { auto exporter = opentelemetry::exporter::trace::OStreamSpanExporterFactory::Create(); auto processor = @@ -80,6 +80,12 @@ void initTracer() new opentelemetry::trace::propagation::HttpTraceContext())); } +void CleanupTracer() +{ + std::shared_ptr none; + opentelemetry::trace::Provider::SetTracerProvider(none); +} + opentelemetry::nostd::shared_ptr get_tracer(std::string tracer_name) { auto provider = opentelemetry::trace::Provider::GetTracerProvider(); diff --git a/examples/jaeger/BUILD b/examples/jaeger/BUILD index 23f42f93b2..e2f0ec7bce 100644 --- a/examples/jaeger/BUILD +++ b/examples/jaeger/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + cc_binary( name = "example_jaeger", srcs = [ diff --git a/examples/jaeger/CMakeLists.txt b/examples/jaeger/CMakeLists.txt index 713521c3a7..0c75ff4b6d 100644 --- a/examples/jaeger/CMakeLists.txt +++ b/examples/jaeger/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + include_directories(${CMAKE_SOURCE_DIR}/exporters/jaeger/include) add_executable(example_jaeger main.cc) diff --git a/examples/jaeger/main.cc b/examples/jaeger/main.cc index 2756f4ce2c..faa9758f02 100644 --- a/examples/jaeger/main.cc +++ b/examples/jaeger/main.cc @@ -13,7 +13,6 @@ #endif namespace trace = opentelemetry::trace; -namespace nostd = opentelemetry::nostd; namespace trace_sdk = opentelemetry::sdk::trace; namespace jaeger = opentelemetry::exporter::jaeger; @@ -30,6 +29,12 @@ void InitTracer() // Set the global trace provider trace::Provider::SetTracerProvider(provider); } + +void CleanupTracer() +{ + std::shared_ptr none; + trace::Provider::SetTracerProvider(none); +} } // namespace int main(int argc, char *argv[]) @@ -42,4 +47,6 @@ int main(int argc, char *argv[]) InitTracer(); foo_library(); + + CleanupTracer(); } diff --git a/examples/logs_simple/BUILD b/examples/logs_simple/BUILD new file mode 100644 index 0000000000..03073b429c --- /dev/null +++ b/examples/logs_simple/BUILD @@ -0,0 +1,19 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +cc_binary( + name = "example_logs_simple", + srcs = [ + "main.cc", + ], + tags = [ + "examples", + "ostream", + ], + deps = [ + "//api", + "//examples/common/logs_foo_library:common_logs_foo_library", + "//exporters/ostream:ostream_log_record_exporter", + "//exporters/ostream:ostream_span_exporter", + ], +) diff --git a/examples/logs_simple/CMakeLists.txt b/examples/logs_simple/CMakeLists.txt new file mode 100644 index 0000000000..7b4548ec52 --- /dev/null +++ b/examples/logs_simple/CMakeLists.txt @@ -0,0 +1,22 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +if(DEFINED OPENTELEMETRY_BUILD_DLL) + add_definitions(-DOPENTELEMETRY_BUILD_IMPORT_DLL) +endif() + +include_directories(${CMAKE_SOURCE_DIR}/exporters/ostream/include) + +if(WITH_LOGS_PREVIEW) + add_executable(example_logs_simple main.cc) + target_link_libraries(example_logs_simple ${CMAKE_THREAD_LIBS_INIT} + common_logs_foo_library) + + if(DEFINED OPENTELEMETRY_BUILD_DLL) + target_link_libraries(example_logs_simple opentelemetry_cpp) + else() + target_link_libraries( + example_logs_simple opentelemetry_trace opentelemetry_logs + opentelemetry_exporter_ostream_span opentelemetry_exporter_ostream_logs) + endif() +endif() diff --git a/examples/logs_simple/README.md b/examples/logs_simple/README.md new file mode 100644 index 0000000000..24db84bc08 --- /dev/null +++ b/examples/logs_simple/README.md @@ -0,0 +1,16 @@ + +# Simple Logs Example + +In this example, the application in `main.cc` initializes an +`OStreamLogRecordExporter` instance and registers a logger +provider, as well as initializes a `StdoutSpanExporter` instance and registers a +tracer provider from the [OpenTelemetry +SDK](https://github.com/open-telemetry/opentelemetry-cpp). + +The application then calls a `logs_foo_library` which has been instrumented +using the [OpenTelemetry +API](https://github.com/open-telemetry/opentelemetry-cpp/tree/main/api). +Resulting logs and traces are directed to stdout. + +See [CONTRIBUTING.md](../../CONTRIBUTING.md) for instructions on building and +running the example. diff --git a/examples/logs_simple/main.cc b/examples/logs_simple/main.cc new file mode 100644 index 0000000000..f4bcecbb39 --- /dev/null +++ b/examples/logs_simple/main.cc @@ -0,0 +1,83 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifdef ENABLE_LOGS_PREVIEW +# include "opentelemetry/exporters/ostream/span_exporter_factory.h" +# include "opentelemetry/sdk/trace/simple_processor_factory.h" +# include "opentelemetry/sdk/trace/tracer_provider_factory.h" +# include "opentelemetry/trace/provider.h" + +# include "opentelemetry/exporters/ostream/log_record_exporter.h" +# include "opentelemetry/logs/provider.h" +# include "opentelemetry/sdk/logs/logger_provider_factory.h" +# include "opentelemetry/sdk/logs/simple_log_record_processor_factory.h" + +# ifdef BAZEL_BUILD +# include "examples/common/logs_foo_library/foo_library.h" +# else +# include "logs_foo_library/foo_library.h" +# endif + +namespace logs_api = opentelemetry::logs; +namespace logs_sdk = opentelemetry::sdk::logs; +namespace logs_exporter = opentelemetry::exporter::logs; + +namespace trace_api = opentelemetry::trace; +namespace trace_sdk = opentelemetry::sdk::trace; +namespace trace_exporter = opentelemetry::exporter::trace; + +namespace +{ +void InitTracer() +{ + // Create ostream span exporter instance + auto exporter = trace_exporter::OStreamSpanExporterFactory::Create(); + auto processor = trace_sdk::SimpleSpanProcessorFactory::Create(std::move(exporter)); + std::shared_ptr provider = + trace_sdk::TracerProviderFactory::Create(std::move(processor)); + + // Set the global trace provider + trace_api::Provider::SetTracerProvider(provider); +} + +void CleanupTracer() +{ + std::shared_ptr none; + trace_api::Provider::SetTracerProvider(none); +} + +void InitLogger() +{ + // Create ostream log exporter instance + auto exporter = + std::unique_ptr(new logs_exporter::OStreamLogRecordExporter); + auto processor = logs_sdk::SimpleLogRecordProcessorFactory::Create(std::move(exporter)); + std::shared_ptr provider( + logs_sdk::LoggerProviderFactory::Create(std::move(processor))); + + // Set the global logger provider + logs_api::Provider::SetLoggerProvider(provider); +} + +void CleanupLogger() +{ + std::shared_ptr none; + logs_api::Provider::SetLoggerProvider(none); +} + +} // namespace + +int main() +{ + InitTracer(); + InitLogger(); + foo_library(); + CleanupTracer(); + CleanupLogger(); +} +#else +int main() +{ + return 0; +} +#endif // ENABLE_LOGS_PREVIEW diff --git a/examples/metrics_simple/BUILD b/examples/metrics_simple/BUILD index c75822cfd3..029fda8a7a 100644 --- a/examples/metrics_simple/BUILD +++ b/examples/metrics_simple/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + cc_binary( name = "metrics_ostream_example", srcs = [ diff --git a/examples/metrics_simple/CMakeLists.txt b/examples/metrics_simple/CMakeLists.txt index a3caf9b9e6..2018ed808c 100644 --- a/examples/metrics_simple/CMakeLists.txt +++ b/examples/metrics_simple/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + include_directories(${CMAKE_SOURCE_DIR}/exporters/ostream/include) add_executable(metrics_ostream_example metrics_ostream.cc) target_link_libraries( diff --git a/examples/metrics_simple/metrics_ostream.cc b/examples/metrics_simple/metrics_ostream.cc index 4804d88611..ce28b83d90 100644 --- a/examples/metrics_simple/metrics_ostream.cc +++ b/examples/metrics_simple/metrics_ostream.cc @@ -18,7 +18,6 @@ #endif namespace metric_sdk = opentelemetry::sdk::metrics; -namespace nostd = opentelemetry::nostd; namespace common = opentelemetry::common; namespace exportermetrics = opentelemetry::exporter::metrics; namespace metrics_api = opentelemetry::metrics; @@ -26,7 +25,7 @@ namespace metrics_api = opentelemetry::metrics; namespace { -void initMetrics(const std::string &name) +void InitMetrics(const std::string &name) { std::unique_ptr exporter{ new exportermetrics::OStreamMetricExporter}; @@ -75,14 +74,20 @@ void initMetrics(const std::string &name) std::shared_ptr aggregation_config{ new opentelemetry::sdk::metrics::HistogramAggregationConfig}; static_cast(aggregation_config.get()) - ->boundaries_ = std::list{0.0, 50.0, 100.0, 250.0, 500.0, 750.0, - 1000.0, 2500.0, 5000.0, 10000.0, 20000.0}; + ->boundaries_ = std::vector{0.0, 50.0, 100.0, 250.0, 500.0, 750.0, + 1000.0, 2500.0, 5000.0, 10000.0, 20000.0}; std::unique_ptr histogram_view{new metric_sdk::View{ name, "description", metric_sdk::AggregationType::kHistogram, aggregation_config}}; p->AddView(std::move(histogram_instrument_selector), std::move(histogram_meter_selector), std::move(histogram_view)); metrics_api::Provider::SetMeterProvider(provider); } + +void CleanupMetrics() +{ + std::shared_ptr none; + metrics_api::Provider::SetMeterProvider(none); +} } // namespace int main(int argc, char **argv) @@ -94,7 +99,7 @@ int main(int argc, char **argv) } std::string name{"ostream_metric_example"}; - initMetrics(name); + InitMetrics(name); if (example_type == "counter") { @@ -123,4 +128,6 @@ int main(int argc, char **argv) observable_counter_example.join(); histogram_example.join(); } + + CleanupMetrics(); } diff --git a/examples/multi_processor/BUILD b/examples/multi_processor/BUILD index 3388d3942f..1c7a3789b5 100644 --- a/examples/multi_processor/BUILD +++ b/examples/multi_processor/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + cc_binary( name = "example_multi_processor", srcs = [ diff --git a/examples/multi_processor/CMakeLists.txt b/examples/multi_processor/CMakeLists.txt index 1e136e0aa9..803464b8ab 100644 --- a/examples/multi_processor/CMakeLists.txt +++ b/examples/multi_processor/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + include_directories(${CMAKE_SOURCE_DIR}/exporters/ostream/include ${CMAKE_SOURCE_DIR}/exporters/memory/include) diff --git a/examples/multi_processor/main.cc b/examples/multi_processor/main.cc index 86686daa79..10fe606b30 100644 --- a/examples/multi_processor/main.cc +++ b/examples/multi_processor/main.cc @@ -18,11 +18,10 @@ using opentelemetry::exporter::memory::InMemorySpanData; namespace trace_api = opentelemetry::trace; namespace trace_sdk = opentelemetry::sdk::trace; -namespace nostd = opentelemetry::nostd; namespace { -std::shared_ptr initTracer() +std::shared_ptr InitTracer() { std::shared_ptr data; @@ -44,6 +43,12 @@ std::shared_ptr initTracer() return data; } +void CleanupTracer() +{ + std::shared_ptr none; + trace_api::Provider::SetTracerProvider(none); +} + void dumpSpans(std::vector> &spans) { char span_buf[trace_api::SpanId::kSize * 2]; @@ -79,9 +84,11 @@ void dumpSpans(std::vector> &spans) int main() { // Removing this line will leave the default noop TracerProvider in place. - std::shared_ptr data = initTracer(); + std::shared_ptr data = InitTracer(); foo_library(); auto memory_spans = data->GetSpans(); dumpSpans(memory_spans); + + CleanupTracer(); } diff --git a/examples/multithreaded/BUILD b/examples/multithreaded/BUILD index 5cac7b6d30..4ee1386298 100644 --- a/examples/multithreaded/BUILD +++ b/examples/multithreaded/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + cc_binary( name = "example_multithreaded", srcs = [ diff --git a/examples/multithreaded/CMakeLists.txt b/examples/multithreaded/CMakeLists.txt index 0721f2e210..56284f1333 100644 --- a/examples/multithreaded/CMakeLists.txt +++ b/examples/multithreaded/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + include_directories(${CMAKE_SOURCE_DIR}/exporters/ostream/include) add_executable(example_multithreaded main.cc) diff --git a/examples/multithreaded/main.cc b/examples/multithreaded/main.cc index 33679f8309..49eaf4d16d 100644 --- a/examples/multithreaded/main.cc +++ b/examples/multithreaded/main.cc @@ -17,7 +17,7 @@ namespace nostd = opentelemetry::nostd; namespace { -void initTracer() +void InitTracer() { auto exporter = opentelemetry::exporter::trace::OStreamSpanExporterFactory::Create(); auto processor = trace_sdk::SimpleSpanProcessorFactory::Create(std::move(exporter)); @@ -28,6 +28,12 @@ void initTracer() trace_api::Provider::SetTracerProvider(provider); } +void CleanupTracer() +{ + std::shared_ptr none; + trace_api::Provider::SetTracerProvider(none); +} + nostd::shared_ptr get_tracer() { auto provider = trace_api::Provider::GetTracerProvider(); @@ -56,10 +62,14 @@ void run_threads() int main() { - initTracer(); + InitTracer(); - auto root_span = get_tracer()->StartSpan(__func__); - trace_api::Scope scope(root_span); + { + auto root_span = get_tracer()->StartSpan(__func__); + trace_api::Scope scope(root_span); + + run_threads(); + } - run_threads(); + CleanupTracer(); } diff --git a/examples/otlp/BUILD b/examples/otlp/BUILD index 9ed87939f6..25c5e84fe7 100644 --- a/examples/otlp/BUILD +++ b/examples/otlp/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + cc_binary( name = "example_otlp_grpc", srcs = [ diff --git a/examples/otlp/CMakeLists.txt b/examples/otlp/CMakeLists.txt index 30ce3cab48..a9263a38b5 100644 --- a/examples/otlp/CMakeLists.txt +++ b/examples/otlp/CMakeLists.txt @@ -1,40 +1,69 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +if(DEFINED OPENTELEMETRY_BUILD_DLL) + add_definitions(-DOPENTELEMETRY_BUILD_IMPORT_DLL) +endif() + include_directories( ${CMAKE_BINARY_DIR}/generated/third_party/opentelemetry-proto ${CMAKE_SOURCE_DIR}/exporters/otlp/include) if(WITH_OTLP_GRPC) add_executable(example_otlp_grpc grpc_main.cc) - target_link_libraries( - example_otlp_grpc ${CMAKE_THREAD_LIBS_INIT} common_foo_library - opentelemetry_trace opentelemetry_exporter_otlp_grpc) + + target_link_libraries(example_otlp_grpc ${CMAKE_THREAD_LIBS_INIT} + common_foo_library) + + if(DEFINED OPENTELEMETRY_BUILD_DLL) + target_link_libraries(example_otlp_grpc opentelemetry_cpp) + else() + target_link_libraries(example_otlp_grpc opentelemetry_trace + opentelemetry_exporter_otlp_grpc) + endif() if(WITH_LOGS_PREVIEW) add_executable(example_otlp_grpc_log grpc_log_main.cc) - target_link_libraries( - example_otlp_grpc_log - ${CMAKE_THREAD_LIBS_INIT} - common_logs_foo_library - opentelemetry_trace - opentelemetry_logs - opentelemetry_exporter_otlp_grpc - opentelemetry_exporter_otlp_grpc_log) + + target_link_libraries(example_otlp_grpc_log ${CMAKE_THREAD_LIBS_INIT} + common_logs_foo_library) + if(DEFINED OPENTELEMETRY_BUILD_DLL) + target_link_libraries(example_otlp_grpc_log opentelemetry_cpp) + else() + target_link_libraries( + example_otlp_grpc_log opentelemetry_trace opentelemetry_logs + opentelemetry_exporter_otlp_grpc opentelemetry_exporter_otlp_grpc_log) + endif() endif() endif() if(WITH_OTLP_HTTP) add_executable(example_otlp_http http_main.cc) - target_link_libraries( - example_otlp_http ${CMAKE_THREAD_LIBS_INIT} common_foo_library - opentelemetry_trace opentelemetry_exporter_otlp_http) + + target_link_libraries(example_otlp_http ${CMAKE_THREAD_LIBS_INIT} + common_foo_library) + if(DEFINED OPENTELEMETRY_BUILD_DLL) + target_link_libraries(example_otlp_http opentelemetry_cpp + opentelemetry_common) + else() + target_link_libraries(example_otlp_http opentelemetry_trace + opentelemetry_exporter_otlp_http) + endif() + if(WITH_LOGS_PREVIEW) add_executable(example_otlp_http_log http_log_main.cc) - target_link_libraries( - example_otlp_http_log - ${CMAKE_THREAD_LIBS_INIT} - common_logs_foo_library - opentelemetry_trace - opentelemetry_logs - opentelemetry_exporter_otlp_http - opentelemetry_exporter_otlp_http_log) + target_link_libraries(example_otlp_http_log ${CMAKE_THREAD_LIBS_INIT} + common_logs_foo_library) + + if(DEFINED OPENTELEMETRY_BUILD_DLL) + target_link_libraries(example_otlp_http_log opentelemetry_cpp + opentelemetry_common) + else() + target_link_libraries( + example_otlp_http_log common_logs_foo_library opentelemetry_trace + opentelemetry_logs opentelemetry_exporter_otlp_http + opentelemetry_exporter_otlp_http_log) + endif() + endif() endif() diff --git a/examples/otlp/README.md b/examples/otlp/README.md index 43010e6d79..e845786346 100644 --- a/examples/otlp/README.md +++ b/examples/otlp/README.md @@ -31,7 +31,7 @@ API](https://github.com/open-telemetry/opentelemetry-cpp/tree/main/api). To enable TLS authentication for OTLP grpc exporter, SslCredentials can be used by specifying the path to client certificate pem file, or the string containing this certificate via OtlpGrpcExporterOptions. The path to such a .pem file can be -provided as a command-line argument alongwith the collector endpoint to the main +provided as a command-line argument along with the collector endpoint to the main binary invocation above. ### Running OpenTelemetry Collector as docker container diff --git a/examples/otlp/grpc_log_main.cc b/examples/otlp/grpc_log_main.cc index 2dcfd92f1a..e0c85c38c2 100644 --- a/examples/otlp/grpc_log_main.cc +++ b/examples/otlp/grpc_log_main.cc @@ -11,6 +11,11 @@ # include "opentelemetry/sdk/trace/tracer_provider_factory.h" # include "opentelemetry/trace/provider.h" +// sdk::TracerProvider and sdk::LoggerProvider is just used to call ForceFlush and prevent to cancel +// running exportings when destroy and shutdown exporters.It's optional to users. +# include "opentelemetry/sdk/logs/logger_provider.h" +# include "opentelemetry/sdk/trace/tracer_provider.h" + # include # ifdef BAZEL_BUILD @@ -40,6 +45,20 @@ void InitTracer() trace::Provider::SetTracerProvider(provider); } +void CleanupTracer() +{ + // We call ForceFlush to prevent to cancel running exportings, It's optional. + opentelemetry::nostd::shared_ptr provider = + trace::Provider::GetTracerProvider(); + if (provider) + { + static_cast(provider.get())->ForceFlush(); + } + + std::shared_ptr none; + trace::Provider::SetTracerProvider(none); +} + void InitLogger() { // Create OTLP exporter instance @@ -50,6 +69,20 @@ void InitLogger() opentelemetry::logs::Provider::SetLoggerProvider(provider); } + +void CleanupLogger() +{ + // We call ForceFlush to prevent to cancel running exportings, It's optional. + opentelemetry::nostd::shared_ptr provider = + logs::Provider::GetLoggerProvider(); + if (provider) + { + static_cast(provider.get())->ForceFlush(); + } + + nostd::shared_ptr none; + opentelemetry::logs::Provider::SetLoggerProvider(none); +} } // namespace int main(int argc, char *argv[]) @@ -66,6 +99,8 @@ int main(int argc, char *argv[]) InitLogger(); InitTracer(); foo_library(); + CleanupTracer(); + CleanupLogger(); } #else int main() diff --git a/examples/otlp/grpc_main.cc b/examples/otlp/grpc_main.cc index 7d3dd3e4a8..d7e3b29d6c 100644 --- a/examples/otlp/grpc_main.cc +++ b/examples/otlp/grpc_main.cc @@ -6,6 +6,10 @@ #include "opentelemetry/sdk/trace/tracer_provider_factory.h" #include "opentelemetry/trace/provider.h" +// sdk::TracerProvider is just used to call ForceFlush and prevent to cancel running exportings when +// destroy and shutdown exporters.It's optional to users. +#include "opentelemetry/sdk/trace/tracer_provider.h" + #ifdef BAZEL_BUILD # include "examples/common/foo_library/foo_library.h" #else @@ -13,7 +17,6 @@ #endif namespace trace = opentelemetry::trace; -namespace nostd = opentelemetry::nostd; namespace trace_sdk = opentelemetry::sdk::trace; namespace otlp = opentelemetry::exporter::otlp; @@ -30,6 +33,20 @@ void InitTracer() // Set the global trace provider trace::Provider::SetTracerProvider(provider); } + +void CleanupTracer() +{ + // We call ForceFlush to prevent to cancel running exportings, It's optional. + opentelemetry::nostd::shared_ptr provider = + trace::Provider::GetTracerProvider(); + if (provider) + { + static_cast(provider.get())->ForceFlush(); + } + + std::shared_ptr none; + trace::Provider::SetTracerProvider(none); +} } // namespace int main(int argc, char *argv[]) @@ -47,4 +64,6 @@ int main(int argc, char *argv[]) InitTracer(); foo_library(); + + CleanupTracer(); } diff --git a/examples/otlp/grpc_metric_main.cc b/examples/otlp/grpc_metric_main.cc index d2006c9fb7..4417665da6 100644 --- a/examples/otlp/grpc_metric_main.cc +++ b/examples/otlp/grpc_metric_main.cc @@ -18,7 +18,6 @@ #endif namespace metric_sdk = opentelemetry::sdk::metrics; -namespace nostd = opentelemetry::nostd; namespace common = opentelemetry::common; namespace metrics_api = opentelemetry::metrics; namespace otlp_exporter = opentelemetry::exporter::otlp; @@ -28,7 +27,7 @@ namespace otlp_exporter::OtlpGrpcMetricExporterOptions options; -void initMetrics() +void InitMetrics() { auto exporter = otlp_exporter::OtlpGrpcMetricExporterFactory::Create(options); @@ -47,6 +46,12 @@ void initMetrics() metrics_api::Provider::SetMeterProvider(provider); } + +void CleanupMetrics() +{ + std::shared_ptr none; + metrics_api::Provider::SetMeterProvider(none); +} } // namespace int main(int argc, char *argv[]) @@ -66,7 +71,7 @@ int main(int argc, char *argv[]) } } // Removing this line will leave the default noop MetricProvider in place. - initMetrics(); + InitMetrics(); std::string name{"otlp_grpc_metric_example"}; if (example_type == "counter") @@ -96,4 +101,6 @@ int main(int argc, char *argv[]) observable_counter_example.join(); histogram_example.join(); } + + CleanupMetrics(); } diff --git a/examples/otlp/http_log_main.cc b/examples/otlp/http_log_main.cc index f8580d703f..a1171b04e0 100644 --- a/examples/otlp/http_log_main.cc +++ b/examples/otlp/http_log_main.cc @@ -13,6 +13,12 @@ # include "opentelemetry/sdk/trace/tracer_provider_factory.h" # include "opentelemetry/trace/provider.h" +// sdk::TracerProvider and sdk::LoggerProvider is just used to call ForceFlush and prevent to cancel +// running exportings when destroy and shutdown exporters.It's optional to users. +# include "opentelemetry/sdk/logs/logger_provider.h" +# include "opentelemetry/sdk/trace/tracer_provider.h" + +# include # include # ifdef BAZEL_BUILD @@ -22,7 +28,6 @@ # endif namespace trace = opentelemetry::trace; -namespace nostd = opentelemetry::nostd; namespace otlp = opentelemetry::exporter::otlp; namespace logs_sdk = opentelemetry::sdk::logs; namespace logs = opentelemetry::logs; @@ -33,11 +38,27 @@ namespace internal_log = opentelemetry::sdk::common::internal_log; namespace { -opentelemetry::exporter::otlp::OtlpHttpExporterOptions opts; +opentelemetry::exporter::otlp::OtlpHttpExporterOptions trace_opts; void InitTracer() { + if (trace_opts.url.size() > 9) + { + if (trace_opts.url.substr(trace_opts.url.size() - 8) == "/v1/logs") + { + trace_opts.url = trace_opts.url.substr(0, trace_opts.url.size() - 8) + "/v1/traces"; + } + else if (trace_opts.url.substr(trace_opts.url.size() - 9) == "/v1/logs/") + { + trace_opts.url = trace_opts.url.substr(0, trace_opts.url.size() - 9) + "/v1/traces"; + } + else + { + trace_opts.url = opentelemetry::exporter::otlp::GetOtlpDefaultHttpTracesEndpoint(); + } + } + std::cout << "Using " << trace_opts.url << " to export trace spans." << std::endl; // Create OTLP exporter instance - auto exporter = otlp::OtlpHttpExporterFactory::Create(opts); + auto exporter = otlp::OtlpHttpExporterFactory::Create(trace_opts); auto processor = trace_sdk::SimpleSpanProcessorFactory::Create(std::move(exporter)); std::shared_ptr provider = trace_sdk::TracerProviderFactory::Create(std::move(processor)); @@ -45,9 +66,24 @@ void InitTracer() trace::Provider::SetTracerProvider(provider); } +void CleanupTracer() +{ + // We call ForceFlush to prevent to cancel running exportings, It's optional. + opentelemetry::nostd::shared_ptr provider = + trace::Provider::GetTracerProvider(); + if (provider) + { + static_cast(provider.get())->ForceFlush(); + } + + std::shared_ptr none; + trace::Provider::SetTracerProvider(none); +} + opentelemetry::exporter::otlp::OtlpHttpLogRecordExporterOptions logger_opts; void InitLogger() { + std::cout << "Using " << logger_opts.url << " to export log records." << std::endl; logger_opts.console_debug = true; // Create OTLP exporter instance auto exporter = otlp::OtlpHttpLogRecordExporterFactory::Create(logger_opts); @@ -57,6 +93,20 @@ void InitLogger() opentelemetry::logs::Provider::SetLoggerProvider(provider); } + +void CleanupLogger() +{ + // We call ForceFlush to prevent to cancel running exportings, It's optional. + opentelemetry::nostd::shared_ptr provider = + logs::Provider::GetLoggerProvider(); + if (provider) + { + static_cast(provider.get())->ForceFlush(); + } + + std::shared_ptr none; + opentelemetry::logs::Provider::SetLoggerProvider(none); +} } // namespace /* @@ -72,12 +122,12 @@ int main(int argc, char *argv[]) { if (argc > 1) { - opts.url = argv[1]; + trace_opts.url = argv[1]; logger_opts.url = argv[1]; if (argc > 2) { - std::string debug = argv[2]; - opts.console_debug = debug != "" && debug != "0" && debug != "no"; + std::string debug = argv[2]; + trace_opts.console_debug = debug != "" && debug != "0" && debug != "no"; } if (argc > 3) @@ -85,13 +135,13 @@ int main(int argc, char *argv[]) std::string binary_mode = argv[3]; if (binary_mode.size() >= 3 && binary_mode.substr(0, 3) == "bin") { - opts.content_type = opentelemetry::exporter::otlp::HttpRequestContentType::kBinary; + trace_opts.content_type = opentelemetry::exporter::otlp::HttpRequestContentType::kBinary; logger_opts.content_type = opentelemetry::exporter::otlp::HttpRequestContentType::kBinary; } } } - if (opts.console_debug) + if (trace_opts.console_debug) { internal_log::GlobalLogHandler::SetLogLevel(internal_log::LogLevel::Debug); } @@ -99,6 +149,8 @@ int main(int argc, char *argv[]) InitLogger(); InitTracer(); foo_library(); + CleanupTracer(); + CleanupLogger(); } #else int main() diff --git a/examples/otlp/http_main.cc b/examples/otlp/http_main.cc index 8c52dba2b1..09b8daeee2 100644 --- a/examples/otlp/http_main.cc +++ b/examples/otlp/http_main.cc @@ -8,6 +8,10 @@ #include "opentelemetry/sdk/trace/tracer_provider_factory.h" #include "opentelemetry/trace/provider.h" +// sdk::TracerProvider is just used to call ForceFlush and prevent to cancel running exportings when +// destroy and shutdown exporters.It's optional to users. +#include "opentelemetry/sdk/trace/tracer_provider.h" + #include #ifdef BAZEL_BUILD @@ -17,7 +21,6 @@ #endif namespace trace = opentelemetry::trace; -namespace nostd = opentelemetry::nostd; namespace trace_sdk = opentelemetry::sdk::trace; namespace otlp = opentelemetry::exporter::otlp; @@ -36,6 +39,20 @@ void InitTracer() // Set the global trace provider trace::Provider::SetTracerProvider(provider); } + +void CleanupTracer() +{ + // We call ForceFlush to prevent to cancel running exportings, It's optional. + opentelemetry::nostd::shared_ptr provider = + trace::Provider::GetTracerProvider(); + if (provider) + { + static_cast(provider.get())->ForceFlush(); + } + + std::shared_ptr none; + trace::Provider::SetTracerProvider(none); +} } // namespace /* @@ -77,4 +94,6 @@ int main(int argc, char *argv[]) InitTracer(); foo_library(); + + CleanupTracer(); } diff --git a/examples/otlp/opentelemetry-collector-config/config.dev.yaml b/examples/otlp/opentelemetry-collector-config/config.dev.yaml index 895d70ece1..267b7250d6 100644 --- a/examples/otlp/opentelemetry-collector-config/config.dev.yaml +++ b/examples/otlp/opentelemetry-collector-config/config.dev.yaml @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + exporters: logging: loglevel: DEBUG diff --git a/examples/plugin/CMakeLists.txt b/examples/plugin/CMakeLists.txt index 081d08b0a3..e1a44690e4 100644 --- a/examples/plugin/CMakeLists.txt +++ b/examples/plugin/CMakeLists.txt @@ -1,2 +1,5 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + add_subdirectory(load) add_subdirectory(plugin) diff --git a/examples/plugin/load/BUILD b/examples/plugin/load/BUILD index 8777c83a97..b129854a41 100644 --- a/examples/plugin/load/BUILD +++ b/examples/plugin/load/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + cc_binary( name = "load_plugin", srcs = [ diff --git a/examples/plugin/load/CMakeLists.txt b/examples/plugin/load/CMakeLists.txt index 4677c2494e..37ddb98130 100644 --- a/examples/plugin/load/CMakeLists.txt +++ b/examples/plugin/load/CMakeLists.txt @@ -1,2 +1,5 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + add_executable(load_plugin_example main.cc) target_link_libraries(load_plugin_example opentelemetry_api ${CMAKE_DL_LIBS}) diff --git a/examples/plugin/plugin/BUILD b/examples/plugin/plugin/BUILD index a26a0c6e28..2f73980665 100644 --- a/examples/plugin/plugin/BUILD +++ b/examples/plugin/plugin/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + cc_binary( name = "example_plugin.so", srcs = [ diff --git a/examples/plugin/plugin/CMakeLists.txt b/examples/plugin/plugin/CMakeLists.txt index c24a8d1a1c..50b247e4b0 100644 --- a/examples/plugin/plugin/CMakeLists.txt +++ b/examples/plugin/plugin/CMakeLists.txt @@ -1,2 +1,5 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + add_library(example_plugin SHARED tracer.cc factory_impl.cc) target_link_libraries(example_plugin opentelemetry_api) diff --git a/examples/prometheus/BUILD b/examples/prometheus/BUILD index edbfde61e6..0a6789f21f 100644 --- a/examples/prometheus/BUILD +++ b/examples/prometheus/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + cc_binary( name = "prometheus_example", srcs = [ diff --git a/examples/prometheus/CMakeLists.txt b/examples/prometheus/CMakeLists.txt index bee3e7f782..a18aaaf574 100644 --- a/examples/prometheus/CMakeLists.txt +++ b/examples/prometheus/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + include_directories(${CMAKE_SOURCE_DIR}/exporters/prometheus/include) add_executable(prometheus_example main.cc) target_link_libraries( diff --git a/examples/prometheus/README.md b/examples/prometheus/README.md index 782e874644..d44007391c 100644 --- a/examples/prometheus/README.md +++ b/examples/prometheus/README.md @@ -11,31 +11,12 @@ ## Export metrics from the application -It is highly recommended to go over the [ostream-metrics](../metrics_simple/README.md) -doc before following along this document. - Run the application with: ```sh bazel run //examples/prometheus:prometheus_example ``` -The main difference between the [ostream-metrics](../metrics_simple/README.md) -example with this one is that the line below is replaced: - -```cpp -std::unique_ptr exporter{ - new exportermetrics::OStreamMetricExporter}; - -``` - -with - -```cpp -std::unique_ptr exporter{ - new metrics_exporter::PrometheusExporter(opts)}; -``` - OpenTelemetry `PrometheusExporter` will export data via the endpoint defined by `metrics_exporter::PrometheusExporterOptions::url`, @@ -46,8 +27,7 @@ graph LR subgraph SDK MeterProvider - MetricReader[PeriodicExportingMetricReader] - PrometheusExporter["PrometheusExporter
(http://localhost:9464/)"] + MetricReader["PrometheusExporter
(http://localhost:9464/)"] end subgraph API @@ -56,7 +36,7 @@ end Instrument --> | Measurements | MeterProvider -MeterProvider --> | Metrics | MetricReader --> | Pull | PrometheusExporter +MeterProvider --> | Metrics | MetricReader ``` Also, for our learning purpose, we use a while-loop to keep recoring random @@ -79,7 +59,7 @@ Start the application and keep it running. Now we should be able to see the metrics at [http://localhost:9464/metrics](http://localhost:9464/metrics) from a web browser: -![Browser UI](https://user-images.githubusercontent.com/71217171/168492500-12bd1c99-33ab-4515-a294-17bc349b5d13.png) +![Browser UI](https://user-images.githubusercontent.com/9139451/224979531-beaa4d6e-98ec-4798-9934-ed25c6b196db.png) Now, we understand how we can configure `PrometheusExporter` to export metrics. Next, we are going to learn about how to use Prometheus to collect the metrics. @@ -101,14 +81,6 @@ global: scrape_interval: 5s scrape_timeout: 2s evaluation_interval: 5s -alerting: - alertmanagers: - - follow_redirects: true - scheme: http - timeout: 5s - api_version: v2 - static_configs: - - targets: [localhost:9464] scrape_configs: - job_name: otel static_configs: @@ -134,12 +106,12 @@ docker run -p 9090:9090 -v $(pwd):/etc/prometheus --network="host" prom/promethe To use the graphical interface for viewing our metrics with Prometheus, navigate to [http://localhost:9090/graph](http://localhost:9090/graph), -and type `prometheus_metric_example_bucket` in the expression bar of the UI; -finally, click the execute button. +and type `prometheus_metric_example_histogram_bucket` in the expression bar of +the UI; finally, click the execute button. We should be able to see the following chart from the browser: -![Prometheus UI](https://user-images.githubusercontent.com/71217171/168492437-f9769db1-6f9e-49c6-8ef0-85f5e1188ba0.png) +![Prometheus UI](https://user-images.githubusercontent.com/9139451/224979224-e7d3865a-f56e-4bb9-8aab-e3f81de40d6e.png) From the legend, we can see that the `instance` name and the `job` name are the values we have set in `prometheus.yml`. @@ -184,7 +156,7 @@ Feel free to find some handy PromQL [here](https://promlabs.com/promql-cheat-sheet/). ![Grafana -UI](https://user-images.githubusercontent.com/71217171/168492482-047a4429-4854-4b3c-a2dd-4d75362090d5.png) +UI](https://user-images.githubusercontent.com/9139451/224983906-52e061b8-b561-4414-87e9-68823bbc3ad6.png) ```mermaid graph TD diff --git a/examples/prometheus/main.cc b/examples/prometheus/main.cc index 7742344931..d620c761dd 100644 --- a/examples/prometheus/main.cc +++ b/examples/prometheus/main.cc @@ -18,7 +18,6 @@ #endif namespace metrics_sdk = opentelemetry::sdk::metrics; -namespace nostd = opentelemetry::nostd; namespace common = opentelemetry::common; namespace metrics_exporter = opentelemetry::exporter::metrics; namespace metrics_api = opentelemetry::metrics; @@ -26,7 +25,7 @@ namespace metrics_api = opentelemetry::metrics; namespace { -void initMetrics(const std::string &name, const std::string &addr) +void InitMetrics(const std::string &name, const std::string &addr) { metrics_exporter::PrometheusExporterOptions opts; if (!addr.empty()) @@ -35,21 +34,16 @@ void initMetrics(const std::string &name, const std::string &addr) } std::puts("PrometheusExporter example program running ..."); - std::unique_ptr exporter{ - new metrics_exporter::PrometheusExporter(opts)}; - std::string version{"1.2.0"}; std::string schema{"https://opentelemetry.io/schemas/1.2.0"}; + std::shared_ptr prometheus_exporter( + new metrics_exporter::PrometheusExporter(opts)); + // Initialize and set the global MeterProvider - metrics_sdk::PeriodicExportingMetricReaderOptions options; - options.export_interval_millis = std::chrono::milliseconds(1000); - options.export_timeout_millis = std::chrono::milliseconds(500); - std::unique_ptr reader{ - new metrics_sdk::PeriodicExportingMetricReader(std::move(exporter), options)}; auto provider = std::shared_ptr(new metrics_sdk::MeterProvider()); auto p = std::static_pointer_cast(provider); - p->AddMetricReader(std::move(reader)); + p->AddMetricReader(prometheus_exporter); // counter view std::string counter_name = name + "_counter"; @@ -58,7 +52,7 @@ void initMetrics(const std::string &name, const std::string &addr) std::unique_ptr meter_selector{ new metrics_sdk::MeterSelector(name, version, schema)}; std::unique_ptr sum_view{ - new metrics_sdk::View{name, "description", metrics_sdk::AggregationType::kSum}}; + new metrics_sdk::View{counter_name, "description", metrics_sdk::AggregationType::kSum}}; p->AddView(std::move(instrument_selector), std::move(meter_selector), std::move(sum_view)); // histogram view @@ -67,18 +61,24 @@ void initMetrics(const std::string &name, const std::string &addr) new metrics_sdk::InstrumentSelector(metrics_sdk::InstrumentType::kHistogram, histogram_name)}; std::unique_ptr histogram_meter_selector{ new metrics_sdk::MeterSelector(name, version, schema)}; - std::unique_ptr histogram_view{ - new metrics_sdk::View{name, "description", metrics_sdk::AggregationType::kHistogram}}; + std::unique_ptr histogram_view{new metrics_sdk::View{ + histogram_name, "description", metrics_sdk::AggregationType::kHistogram}}; p->AddView(std::move(histogram_instrument_selector), std::move(histogram_meter_selector), std::move(histogram_view)); metrics_api::Provider::SetMeterProvider(provider); } + +void CleanupMetrics() +{ + std::shared_ptr none; + metrics_api::Provider::SetMeterProvider(none); +} } // namespace int main(int argc, char **argv) { std::string example_type; - std::string addr{"localhost:8080"}; + std::string addr{"localhost:9464"}; if (argc == 1) { std::puts("usage: $prometheus_example "); @@ -94,7 +94,7 @@ int main(int argc, char **argv) } std::string name{"prometheus_metric_example"}; - initMetrics(name, addr); + InitMetrics(name, addr); if (example_type == "counter") { @@ -111,4 +111,6 @@ int main(int argc, char **argv) counter_example.join(); histogram_example.join(); } + + CleanupMetrics(); } diff --git a/examples/prometheus/prometheus.yml b/examples/prometheus/prometheus.yml index 6da75c97a8..31b0f99ffa 100644 --- a/examples/prometheus/prometheus.yml +++ b/examples/prometheus/prometheus.yml @@ -1,15 +1,10 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + global: scrape_interval: 5s scrape_timeout: 2s evaluation_interval: 5s -alerting: - alertmanagers: - - follow_redirects: true - scheme: http - timeout: 5s - api_version: v2 - static_configs: - - targets: [localhost:9464] scrape_configs: - job_name: otel static_configs: diff --git a/examples/prometheus/run.sh b/examples/prometheus/run.sh index 412c6ef454..0802daef33 100644 --- a/examples/prometheus/run.sh +++ b/examples/prometheus/run.sh @@ -1 +1,4 @@ -docker run -p 9090:9090 -v $(pwd):/etc/prometheus --network="host" prom/prometheus \ No newline at end of file +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +docker run -p 9090:9090 -v $(pwd):/etc/prometheus --network="host" prom/prometheus diff --git a/examples/simple/BUILD b/examples/simple/BUILD index 6a5a766465..5a3c27c280 100644 --- a/examples/simple/BUILD +++ b/examples/simple/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + cc_binary( name = "example_simple", srcs = [ diff --git a/examples/simple/CMakeLists.txt b/examples/simple/CMakeLists.txt index 4368039c1d..d4fb19c4db 100644 --- a/examples/simple/CMakeLists.txt +++ b/examples/simple/CMakeLists.txt @@ -1,6 +1,19 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +if(DEFINED OPENTELEMETRY_BUILD_DLL) + add_definitions(-DOPENTELEMETRY_BUILD_IMPORT_DLL) +endif() + include_directories(${CMAKE_SOURCE_DIR}/exporters/ostream/include) add_executable(example_simple main.cc) -target_link_libraries( - example_simple ${CMAKE_THREAD_LIBS_INIT} common_foo_library - opentelemetry_trace opentelemetry_exporter_ostream_span) +target_link_libraries(example_simple ${CMAKE_THREAD_LIBS_INIT} + common_foo_library) + +if(DEFINED OPENTELEMETRY_BUILD_DLL) + target_link_libraries(example_simple opentelemetry_cpp) +else() + target_link_libraries(example_simple opentelemetry_trace + opentelemetry_exporter_ostream_span) +endif() diff --git a/examples/simple/main.cc b/examples/simple/main.cc index dc630f47d9..6a8b28e4dd 100644 --- a/examples/simple/main.cc +++ b/examples/simple/main.cc @@ -18,7 +18,7 @@ namespace trace_exporter = opentelemetry::exporter::trace; namespace { -void initTracer() +void InitTracer() { auto exporter = trace_exporter::OStreamSpanExporterFactory::Create(); auto processor = trace_sdk::SimpleSpanProcessorFactory::Create(std::move(exporter)); @@ -28,12 +28,20 @@ void initTracer() // Set the global trace provider trace_api::Provider::SetTracerProvider(provider); } + +void CleanupTracer() +{ + std::shared_ptr none; + trace_api::Provider::SetTracerProvider(none); +} } // namespace int main() { // Removing this line will leave the default noop TracerProvider in place. - initTracer(); + InitTracer(); foo_library(); + + CleanupTracer(); } diff --git a/examples/zipkin/CMakeLists.txt b/examples/zipkin/CMakeLists.txt index f55f363d72..e3e3a5f55f 100644 --- a/examples/zipkin/CMakeLists.txt +++ b/examples/zipkin/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + include_directories(${CMAKE_SOURCE_DIR}/exporters/zipkin/include) add_executable(example_zipkin main.cc) diff --git a/examples/zipkin/main.cc b/examples/zipkin/main.cc index e916cdf4f8..6788d8cabe 100644 --- a/examples/zipkin/main.cc +++ b/examples/zipkin/main.cc @@ -13,7 +13,6 @@ #endif namespace trace = opentelemetry::trace; -namespace nostd = opentelemetry::nostd; namespace trace_sdk = opentelemetry::sdk::trace; namespace zipkin = opentelemetry::exporter::zipkin; namespace resource = opentelemetry::sdk::resource; @@ -33,6 +32,12 @@ void InitTracer() // Set the global trace provider trace::Provider::SetTracerProvider(provider); } + +void CleanupTracer() +{ + std::shared_ptr none; + trace::Provider::SetTracerProvider(none); +} } // namespace int main(int argc, char *argv[]) @@ -45,4 +50,6 @@ int main(int argc, char *argv[]) InitTracer(); foo_library(); + + CleanupTracer(); } diff --git a/examples/zpages/BUILD b/examples/zpages/BUILD index 4200398c98..529c839cb7 100644 --- a/examples/zpages/BUILD +++ b/examples/zpages/BUILD @@ -1,16 +1,5 @@ -# 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. +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 package(default_visibility = ["//visibility:public"]) diff --git a/exporters/CMakeLists.txt b/exporters/CMakeLists.txt index 862d2c779e..f852f420f5 100644 --- a/exporters/CMakeLists.txt +++ b/exporters/CMakeLists.txt @@ -1,16 +1,5 @@ -# Copyright 2021, 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. +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 if(WITH_OTLP) add_subdirectory(otlp) diff --git a/exporters/elasticsearch/BUILD b/exporters/elasticsearch/BUILD index 16fae2edab..9990c25860 100644 --- a/exporters/elasticsearch/BUILD +++ b/exporters/elasticsearch/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + package(default_visibility = ["//visibility:public"]) cc_library( diff --git a/exporters/elasticsearch/CMakeLists.txt b/exporters/elasticsearch/CMakeLists.txt index 90064e292d..94a12c62e0 100644 --- a/exporters/elasticsearch/CMakeLists.txt +++ b/exporters/elasticsearch/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + add_library(opentelemetry_exporter_elasticsearch_logs src/es_log_record_exporter.cc src/es_log_recordable.cc) @@ -14,19 +17,21 @@ target_link_libraries( PUBLIC opentelemetry_trace opentelemetry_logs opentelemetry_http_client_curl nlohmann_json::nlohmann_json) -install( - TARGETS opentelemetry_exporter_elasticsearch_logs - EXPORT "${PROJECT_NAME}-target" - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - -install( - DIRECTORY include/opentelemetry/exporters/elasticsearch - DESTINATION include/opentelemetry/exporters - FILES_MATCHING - PATTERN "*.h" - PATTERN "es_log_recordable.h" EXCLUDE) +if(OPENTELEMETRY_INSTALL) + install( + TARGETS opentelemetry_exporter_elasticsearch_logs + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + install( + DIRECTORY include/opentelemetry/exporters/elasticsearch + DESTINATION include/opentelemetry/exporters + FILES_MATCHING + PATTERN "*.h" + PATTERN "es_log_recordable.h" EXCLUDE) +endif() if(BUILD_TESTING) add_executable(es_log_record_exporter_test diff --git a/exporters/elasticsearch/include/opentelemetry/exporters/elasticsearch/es_log_record_exporter.h b/exporters/elasticsearch/include/opentelemetry/exporters/elasticsearch/es_log_record_exporter.h index 7a52810df0..06b4c3b727 100644 --- a/exporters/elasticsearch/include/opentelemetry/exporters/elasticsearch/es_log_record_exporter.h +++ b/exporters/elasticsearch/include/opentelemetry/exporters/elasticsearch/es_log_record_exporter.h @@ -7,12 +7,17 @@ # include "nlohmann/json.hpp" # include "opentelemetry/common/spin_lock_mutex.h" # include "opentelemetry/ext/http/client/http_client_factory.h" +# include "opentelemetry/nostd/shared_ptr.h" # include "opentelemetry/nostd/type_traits.h" # include "opentelemetry/sdk/logs/exporter.h" # include "opentelemetry/sdk/logs/recordable.h" # include +# include +# include +# include # include +# include OPENTELEMETRY_BEGIN_NAMESPACE namespace exporter @@ -90,6 +95,14 @@ class ElasticsearchLogRecordExporter final : public opentelemetry::sdk::logs::Lo const opentelemetry::nostd::span> &records) noexcept override; + /** + * Force flush the exporter. + * @param timeout an option timeout, default to max. + * @return return true when all data are exported, and false when timeout + */ + bool ForceFlush( + std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override; + /** * Shutdown this exporter. * @param timeout The maximum time to wait for the shutdown method to return @@ -108,6 +121,18 @@ class ElasticsearchLogRecordExporter final : public opentelemetry::sdk::logs::Lo std::shared_ptr http_client_; mutable opentelemetry::common::SpinLockMutex lock_; bool isShutdown() const noexcept; + +# ifdef ENABLE_ASYNC_EXPORT + struct SynchronizationData + { + std::atomic session_counter_; + std::atomic finished_session_counter_; + std::condition_variable force_flush_cv; + std::mutex force_flush_cv_m; + std::recursive_mutex force_flush_m; + }; + nostd::shared_ptr synchronization_data_; +# endif }; } // namespace logs } // namespace exporter diff --git a/exporters/elasticsearch/src/es_log_record_exporter.cc b/exporters/elasticsearch/src/es_log_record_exporter.cc index c440be685c..14fd87d600 100644 --- a/exporters/elasticsearch/src/es_log_record_exporter.cc +++ b/exporters/elasticsearch/src/es_log_record_exporter.cc @@ -290,9 +290,19 @@ class AsyncResponseHandler : public http_client::EventHandler # endif ElasticsearchLogRecordExporter::ElasticsearchLogRecordExporter() - : options_{ElasticsearchExporterOptions()}, - http_client_{ext::http::client::HttpClientFactory::Create()} -{} + : options_{ElasticsearchExporterOptions()}, http_client_ +{ + ext::http::client::HttpClientFactory::Create() +} +# ifdef ENABLE_ASYNC_EXPORT +, synchronization_data_(new SynchronizationData()) +# endif +{ +# ifdef ENABLE_ASYNC_EXPORT + synchronization_data_->finished_session_counter_.store(0); + synchronization_data_->session_counter_.store(0); +# endif +} ElasticsearchLogRecordExporter::ElasticsearchLogRecordExporter( const ElasticsearchExporterOptions &options) @@ -343,10 +353,12 @@ sdk::common::ExportResult ElasticsearchLogRecordExporter::Export( # ifdef ENABLE_ASYNC_EXPORT // Send the request - std::size_t span_count = records.size(); - auto handler = std::make_shared( + synchronization_data_->session_counter_.fetch_add(1, std::memory_order_release); + std::size_t span_count = records.size(); + auto synchronization_data = synchronization_data_; + auto handler = std::make_shared( session, - [span_count](opentelemetry::sdk::common::ExportResult result) { + [span_count, synchronization_data](opentelemetry::sdk::common::ExportResult result) { if (result != opentelemetry::sdk::common::ExportResult::kSuccess) { OTEL_INTERNAL_LOG_ERROR("[ES Log Exporter] ERROR: Export " @@ -358,6 +370,9 @@ sdk::common::ExportResult ElasticsearchLogRecordExporter::Export( OTEL_INTERNAL_LOG_DEBUG("[ES Log Exporter] Export " << span_count << " trace span(s) success"); } + + synchronization_data->finished_session_counter_.fetch_add(1, std::memory_order_release); + synchronization_data->force_flush_cv.notify_all(); return true; }, options_.console_debug_); @@ -401,6 +416,50 @@ sdk::common::ExportResult ElasticsearchLogRecordExporter::Export( # endif } +bool ElasticsearchLogRecordExporter::ForceFlush( + std::chrono::microseconds timeout OPENTELEMETRY_MAYBE_UNUSED) noexcept +{ +# ifdef ENABLE_ASYNC_EXPORT + std::lock_guard lock_guard{synchronization_data_->force_flush_m}; + std::size_t running_counter = + synchronization_data_->session_counter_.load(std::memory_order_acquire); + // ASAN will report chrono: runtime error: signed integer overflow: A + B cannot be represented + // in type 'long int' here. So we reset timeout to meet signed long int limit here. + timeout = opentelemetry::common::DurationUtil::AdjustWaitForTimeout( + timeout, std::chrono::microseconds::zero()); + + std::chrono::steady_clock::duration timeout_steady = + std::chrono::duration_cast(timeout); + if (timeout_steady <= std::chrono::steady_clock::duration::zero()) + { + timeout_steady = std::chrono::steady_clock::duration::max(); + } + + std::unique_lock lk_cv(synchronization_data_->force_flush_cv_m); + // Wait for all the sessions to finish + while (timeout_steady > std::chrono::steady_clock::duration::zero()) + { + if (synchronization_data_->finished_session_counter_.load(std::memory_order_acquire) >= + running_counter) + { + break; + } + + std::chrono::steady_clock::time_point start_timepoint = std::chrono::steady_clock::now(); + if (std::cv_status::no_timeout != synchronization_data_->force_flush_cv.wait_for( + lk_cv, std::chrono::seconds{options_.response_timeout_})) + { + break; + } + timeout_steady -= std::chrono::steady_clock::now() - start_timepoint; + } + + return timeout_steady > std::chrono::steady_clock::duration::zero(); +# else + return true; +# endif +} + bool ElasticsearchLogRecordExporter::Shutdown(std::chrono::microseconds /* timeout */) noexcept { const std::lock_guard locked(lock_); diff --git a/exporters/etw/BUILD b/exporters/etw/BUILD index c2328ed4e8..ad8518bc25 100644 --- a/exporters/etw/BUILD +++ b/exporters/etw/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + package(default_visibility = ["//visibility:public"]) cc_library( diff --git a/exporters/etw/CMakeLists.txt b/exporters/etw/CMakeLists.txt index 7b092155f2..b74a1b2cb5 100644 --- a/exporters/etw/CMakeLists.txt +++ b/exporters/etw/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + add_library(opentelemetry_exporter_etw INTERFACE) target_include_directories( @@ -8,29 +11,37 @@ target_include_directories( set_target_properties(opentelemetry_exporter_etw PROPERTIES EXPORT_NAME etw_exporter) -target_link_libraries(opentelemetry_exporter_etw - INTERFACE opentelemetry_api nlohmann_json::nlohmann_json) +target_link_libraries( + opentelemetry_exporter_etw INTERFACE opentelemetry_api opentelemetry_trace + nlohmann_json::nlohmann_json) +if(WITH_LOGS_PREVIEW) + target_link_libraries(opentelemetry_exporter_etw INTERFACE opentelemetry_logs) +endif() if(nlohmann_json_clone) add_dependencies(opentelemetry_exporter_etw nlohmann_json::nlohmann_json) endif() -install( - TARGETS opentelemetry_exporter_etw - EXPORT "${PROJECT_NAME}-target" - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +if(OPENTELEMETRY_INSTALL) + install( + TARGETS opentelemetry_exporter_etw + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) -install( - DIRECTORY include/opentelemetry/exporters/etw - DESTINATION include/opentelemetry/exporters - FILES_MATCHING - PATTERN "*.h") + install( + DIRECTORY include/opentelemetry/exporters/etw + DESTINATION include/opentelemetry/exporters + FILES_MATCHING + PATTERN "*.h") +endif() if(BUILD_TESTING) add_executable(etw_provider_test test/etw_provider_test.cc) add_executable(etw_tracer_test test/etw_tracer_test.cc) add_executable(etw_logger_test test/etw_logger_test.cc) + add_executable(etw_tracer_test_enable_env_properties test/etw_tracer_test.cc) + add_executable(etw_logger_test_enable_env_properties test/etw_logger_test.cc) target_link_libraries(etw_provider_test ${GTEST_BOTH_LIBRARIES} opentelemetry_exporter_etw ${CMAKE_THREAD_LIBS_INIT}) @@ -41,6 +52,18 @@ if(BUILD_TESTING) target_link_libraries(etw_logger_test ${GTEST_BOTH_LIBRARIES} opentelemetry_exporter_etw ${CMAKE_THREAD_LIBS_INIT}) + target_link_libraries( + etw_tracer_test_enable_env_properties ${GTEST_BOTH_LIBRARIES} + opentelemetry_exporter_etw ${CMAKE_THREAD_LIBS_INIT}) + target_compile_definitions(etw_tracer_test_enable_env_properties + PRIVATE ENABLE_ENV_PROPERTIES) + + target_link_libraries( + etw_logger_test_enable_env_properties ${GTEST_BOTH_LIBRARIES} + opentelemetry_exporter_etw ${CMAKE_THREAD_LIBS_INIT}) + target_compile_definitions(etw_logger_test_enable_env_properties + PRIVATE ENABLE_ENV_PROPERTIES) + if(WITH_BENCHMARK) add_executable(etw_perf_test test/etw_perf_test.cc) target_link_libraries( @@ -60,5 +83,13 @@ if(BUILD_TESTING) TARGET etw_logger_test TEST_PREFIX exporter. TEST_LIST etw_logger_test) + gtest_add_tests( + TARGET etw_tracer_test_enable_env_properties + TEST_PREFIX exporter.with_env_properties. + TEST_LIST etw_tracer_test_enable_env_properties) + gtest_add_tests( + TARGET etw_logger_test_enable_env_properties + TEST_PREFIX exporter.with_env_properties. + TEST_LIST etw_logger_test_enable_env_properties) endif() # BUILD_TESTING diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_fields.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_fields.h index a2fd6c727c..041929d1c0 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_fields.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_fields.h @@ -131,12 +131,13 @@ # define ETW_VALUE_SPAN_END "SpanEnd" /* ETW for Span Start */ +# define ETW_FIELD_ENV_PROPERTIES "env_properties" /* ETW event_properties with JSON string */ + /* Log specific */ # define ETW_FIELD_LOG_BODY "body" /* Log body */ # define ETW_FIELD_LOG_SEVERITY_TEXT "severityText" /* Sev text */ # define ETW_FIELD_LOG_SEVERITY_NUM "severityNumber" /* Sev num */ - #endif /* clang-format on */ diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_logger.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_logger.h index d72fe64edb..ccf332b599 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_logger.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_logger.h @@ -222,12 +222,51 @@ class Logger : public opentelemetry::logs::Logger virtual void Log(opentelemetry::logs::Severity severity, nostd::string_view name, nostd::string_view body, - Properties &evt, + Properties &input_evt, opentelemetry::trace::TraceId trace_id, opentelemetry::trace::SpanId span_id, opentelemetry::trace::TraceFlags trace_flags, common::SystemTimestamp timestamp) noexcept { + UNREFERENCED_PARAMETER(trace_flags); + +# if defined(ENABLE_ENV_PROPERTIES) + + Properties env_properties_env = {}; + bool has_customer_attribute = false; + if (input_evt.size() > 0) + { + nlohmann::json env_properties_json = nlohmann::json::object(); + for (auto &kv : input_evt) + { + nostd::string_view key = kv.first.data(); + + // don't serialize fields propagated from span data. + if (key == ETW_FIELD_NAME || key == ETW_FIELD_SPAN_ID || key == ETW_FIELD_TRACE_ID || + key == ETW_FIELD_SPAN_PARENTID) + { + env_properties_env[key.data()] = kv.second; + } + else + { + utils::PopulateAttribute(env_properties_json, key, kv.second); + has_customer_attribute = true; + } + } + if (has_customer_attribute) + { + env_properties_env[ETW_FIELD_ENV_PROPERTIES] = env_properties_json.dump(); + } + } + + Properties &evt = has_customer_attribute ? env_properties_env : input_evt; + +# else + + Properties &evt = input_evt; + +# endif // defined(ENABLE_ENV_PROPERTIES) + // Populate Etw.EventName attribute at envelope level evt[ETW_FIELD_NAME] = ETW_VALUE_LOG; @@ -317,44 +356,17 @@ class LoggerProvider : public opentelemetry::logs::LoggerProvider nostd::shared_ptr GetLogger( nostd::string_view logger_name, - nostd::string_view options, - nostd::string_view library_name, - nostd::string_view version = "", - nostd::string_view schema_url = "") override - { - UNREFERENCED_PARAMETER(options); - UNREFERENCED_PARAMETER(library_name); - UNREFERENCED_PARAMETER(version); - UNREFERENCED_PARAMETER(schema_url); - ETWProvider::EventFormat evtFmt = config_.encoding; - return nostd::shared_ptr{ - new (std::nothrow) etw::Logger(*this, logger_name, evtFmt)}; - } - - /** - * @brief Obtain ETW Tracer. - * @param name ProviderId (instrumentation name) - Name or GUID - * @param args Additional arguments that controls `codec` of the provider. - * Possible values are: - * - "ETW" - 'classic' Trace Logging Dynamic manifest ETW events. - * - "MSGPACK" - MessagePack-encoded binary payload ETW events. - * - "XML" - XML events (reserved for future use) - * @param library_name Library name - * @param version Library version - * @param schema_url schema URL - * @return - */ - nostd::shared_ptr GetLogger( - nostd::string_view logger_name, - nostd::span args, nostd::string_view library_name, - nostd::string_view version = "", - nostd::string_view schema_url = "") override + nostd::string_view version = "", + nostd::string_view schema_url = "", + bool include_trace_context = true, + const common::KeyValueIterable &attributes = common::NoopKeyValueIterable()) override { - UNREFERENCED_PARAMETER(args); UNREFERENCED_PARAMETER(library_name); UNREFERENCED_PARAMETER(version); UNREFERENCED_PARAMETER(schema_url); + UNREFERENCED_PARAMETER(include_trace_context); + UNREFERENCED_PARAMETER(attributes); ETWProvider::EventFormat evtFmt = config_.encoding; return nostd::shared_ptr{ new (std::nothrow) etw::Logger(*this, logger_name, evtFmt)}; diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_tail_sampler.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_tail_sampler.h index c4d0a2edd7..bd4a9bb90e 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_tail_sampler.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_tail_sampler.h @@ -21,6 +21,7 @@ class TailSampler // Span::GetContext() virtual opentelemetry::sdk::trace::SamplingResult ShouldSample( const opentelemetry::trace::Span &span) noexcept = 0; + virtual ~TailSampler() = default; }; class AlwaysOnTailSampler : public TailSampler @@ -29,6 +30,7 @@ class AlwaysOnTailSampler : public TailSampler opentelemetry::sdk::trace::SamplingResult ShouldSample( const opentelemetry::trace::Span &span) noexcept override { + UNREFERENCED_PARAMETER(span); return {opentelemetry::sdk::trace::Decision::RECORD_AND_SAMPLE}; } }; diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_traceloggingdynamic.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_traceloggingdynamic.h index a6243c46db..dc5a3356ca 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_traceloggingdynamic.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_traceloggingdynamic.h @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + #pragma once #ifdef __has_include diff --git a/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer.h b/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer.h index 2b0ff4c507..039351f66e 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/etw_tracer.h @@ -250,8 +250,41 @@ class Tracer : public opentelemetry::trace::Tracer, auto spanContext = spanBase.GetContext(); // Populate Span with presaved attributes - Span ¤tSpan = const_cast(span); - Properties evt = GetSpanAttributes(currentSpan); + Span ¤tSpan = const_cast(span); + Properties evt = GetSpanAttributes(currentSpan); + +#if defined(ENABLE_ENV_PROPERTIES) + + Properties env_properties_env = {}; + if (evt.size() > 0) + { + bool has_customer_attribute = false; + nlohmann::json env_properties_json = nlohmann::json::object(); + for (auto &kv : evt) + { + nostd::string_view key = kv.first.data(); + + // don't serialize fields propagated from span data. + if (key == ETW_FIELD_NAME || key == ETW_FIELD_SPAN_ID || key == ETW_FIELD_TRACE_ID || + key == ETW_FIELD_SPAN_PARENTID) + { + env_properties_env[key.data()] = kv.second; + } + else + { + utils::PopulateAttribute(env_properties_json, key, kv.second); + has_customer_attribute = true; + } + } + if (has_customer_attribute) + { + env_properties_env[ETW_FIELD_ENV_PROPERTIES] = env_properties_json.dump(); + evt = std::move(env_properties_env); + } + } + +#endif // defined(ENABLE_ENV_PROPERTIES) + evt[ETW_FIELD_NAME] = GetName(span); if (cfg.enableSpanId) @@ -870,7 +903,8 @@ class Span : public opentelemetry::trace::Span void SetAttribute(nostd::string_view key, const common::AttributeValue &value) noexcept override { // don't override fields propagated from span data. - if (key == ETW_FIELD_NAME || key == ETW_FIELD_SPAN_ID || key == ETW_FIELD_TRACE_ID) + if (key == ETW_FIELD_NAME || key == ETW_FIELD_SPAN_ID || key == ETW_FIELD_TRACE_ID || + key == ETW_FIELD_SPAN_PARENTID) { return; } diff --git a/exporters/etw/include/opentelemetry/exporters/etw/utils.h b/exporters/etw/include/opentelemetry/exporters/etw/utils.h index ef6edc5ca2..6a887b6831 100644 --- a/exporters/etw/include/opentelemetry/exporters/etw/utils.h +++ b/exporters/etw/include/opentelemetry/exporters/etw/utils.h @@ -27,6 +27,13 @@ # include #endif +#if defined(ENABLE_ENV_PROPERTIES) + +# include +# include "etw_properties.h" + +#endif + OPENTELEMETRY_BEGIN_NAMESPACE namespace utils @@ -270,6 +277,112 @@ static inline std::string formatUtcTimestampNsAsISO8601(int64_t timestampNs) return buf; } +#if defined(ENABLE_ENV_PROPERTIES) + +static inline void PopulateAttribute(nlohmann::json &attribute, + nostd::string_view key, + const exporter::etw::PropertyValue &value) +{ + if (nostd::holds_alternative(value)) + { + attribute[key.data()] = nostd::get(value); + } + else if (nostd::holds_alternative(value)) + { + attribute[key.data()] = nostd::get(value); + } + else if (nostd::holds_alternative(value)) + { + attribute[key.data()] = nostd::get(value); + } + else if (nostd::holds_alternative(value)) + { + attribute[key.data()] = nostd::get(value); + } + else if (nostd::holds_alternative(value)) + { + attribute[key.data()] = nostd::get(value); + } + else if (nostd::holds_alternative(value)) + { + attribute[key.data()] = nostd::get(value); + } + else if (nostd::holds_alternative(value)) + { + attribute[key.data()] = std::string(nostd::get(value)); + } + else if (nostd::holds_alternative(value)) + { + attribute[key.data()] = nostd::get(value); + } + else if (nostd::holds_alternative>(value)) + { + attribute[key.data()] = {}; + for (const auto &val : nostd::get>(value)) + { + attribute[key.data()].push_back(val); + } + } + else if (nostd::holds_alternative>(value)) + { + attribute[key.data()] = {}; + for (const auto &val : nostd::get>(value)) + { + attribute[key.data()].push_back(val); + } + } + else if (nostd::holds_alternative>(value)) + { + attribute[key.data()] = {}; + for (const auto &val : nostd::get>(value)) + { + attribute[key.data()].push_back(val); + } + } + else if (nostd::holds_alternative>(value)) + { + attribute[key.data()] = {}; + for (const auto &val : nostd::get>(value)) + { + attribute[key.data()].push_back(val); + } + } + else if (nostd::holds_alternative>(value)) + { + attribute[key.data()] = {}; + for (const auto &val : nostd::get>(value)) + { + attribute[key.data()].push_back(val); + } + } + else if (nostd::holds_alternative>(value)) + { + attribute[key.data()] = {}; + for (const auto &val : nostd::get>(value)) + { + attribute[key.data()].push_back(val); + } + } + else if (nostd::holds_alternative>(value)) + { + attribute[key.data()] = {}; + for (const auto &val : nostd::get>(value)) + { + attribute[key.data()].push_back(val); + } + } + else if (nostd::holds_alternative>(value)) + { + attribute[key.data()] = {}; + for (const auto &val : nostd::get>(value)) + { + attribute[key.data()].push_back(val); + } + } +} + +#endif // defined(ENABLE_ENV_PROPERTIES) + }; // namespace utils OPENTELEMETRY_END_NAMESPACE diff --git a/exporters/etw/test/etw_logger_test.cc b/exporters/etw/test/etw_logger_test.cc index 7d9040b553..2c17dc846e 100644 --- a/exporters/etw/test/etw_logger_test.cc +++ b/exporters/etw/test/etw_logger_test.cc @@ -49,9 +49,10 @@ TEST(ETWLogger, LoggerCheckWithBody) exporter::etw::LoggerProvider lp; const std::string schema_url{"https://opentelemetry.io/schemas/1.2.0"}; - auto logger = lp.GetLogger(providerName, "", schema_url); + auto logger = lp.GetLogger(providerName, schema_url); Properties attribs = {{"attrib1", 1}, {"attrib2", 2}}; - EXPECT_NO_THROW(logger->Log(opentelemetry::logs::Severity::kDebug, "This is test log body")); + EXPECT_NO_THROW( + logger->EmitLogRecord(opentelemetry::logs::Severity::kDebug, "This is test log body")); } /** @@ -91,10 +92,11 @@ TEST(ETWLogger, LoggerCheckWithAttributes) exporter::etw::LoggerProvider lp; const std::string schema_url{"https://opentelemetry.io/schemas/1.2.0"}; - auto logger = lp.GetLogger(providerName, "", schema_url); + auto logger = lp.GetLogger(providerName, schema_url); // Log attributes Properties attribs = {{"attrib1", 1}, {"attrib2", 2}}; - EXPECT_NO_THROW(logger->Log(opentelemetry::logs::Severity::kDebug, attribs)); + EXPECT_NO_THROW(logger->EmitLogRecord(opentelemetry::logs::Severity::kDebug, + opentelemetry::common::MakeAttributes(attribs))); } # endif // _WIN32 diff --git a/exporters/etw/test/etw_tracer_test.cc b/exporters/etw/test/etw_tracer_test.cc index 9095de4961..a7aa6b168b 100644 --- a/exporters/etw/test/etw_tracer_test.cc +++ b/exporters/etw/test/etw_tracer_test.cc @@ -117,22 +117,25 @@ TEST(ETWTracer, TracerCheck) auto tracer = tp.GetTracer(providerName); // Span attributes - Properties attribs = + Properties outer_attribs = { {"attrib1", 1}, {"attrib2", 2} }; + // copy the outer attributes + Properties inner_attribs = outer_attribs; + { auto topSpan = tracer->StartSpan("MySpanTop"); auto topScope = tracer->WithActiveSpan(topSpan); { - auto outerSpan = tracer->StartSpan("MySpanL2", attribs); + auto outerSpan = tracer->StartSpan("MySpanL2", outer_attribs); auto outerScope = tracer->WithActiveSpan(outerSpan); // Create nested span. Note how we share the attributes here. // It is Okay to either reuse/share or have your own attributes. { - auto innerSpan = tracer->StartSpan("MySpanL3", attribs); + auto innerSpan = tracer->StartSpan("MySpanL3", inner_attribs); auto innerScope = tracer->WithActiveSpan(innerSpan); // Add span attribute diff --git a/exporters/jaeger/BUILD b/exporters/jaeger/BUILD index b316fd88a0..6f0e030b4d 100644 --- a/exporters/jaeger/BUILD +++ b/exporters/jaeger/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + package(default_visibility = ["//visibility:public"]) load("@rules_foreign_cc//foreign_cc:defs.bzl", "cmake", "configure_make", "configure_make_variant") @@ -186,6 +189,7 @@ cc_library( deps = [ ":jaeger_exporter", "//sdk/src/common:global_log_handler", + "//sdk/src/trace", ], ) diff --git a/exporters/jaeger/CMakeLists.txt b/exporters/jaeger/CMakeLists.txt index 9641300124..a02fa7c3e5 100644 --- a/exporters/jaeger/CMakeLists.txt +++ b/exporters/jaeger/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + include_directories(thrift-gen) find_package(Thrift REQUIRED) @@ -40,7 +43,8 @@ target_include_directories( target_link_libraries( opentelemetry_exporter_jaeger_trace - PUBLIC opentelemetry_resources opentelemetry_http_client_curl + PUBLIC opentelemetry_resources opentelemetry_trace + opentelemetry_http_client_curl PRIVATE thrift::thrift) if(MSVC) @@ -52,19 +56,21 @@ if(MSVC) endif() endif() -install( - TARGETS opentelemetry_exporter_jaeger_trace - EXPORT "${PROJECT_NAME}-target" - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - -install( - DIRECTORY include/opentelemetry/exporters/jaeger - DESTINATION include/opentelemetry/exporters - FILES_MATCHING - PATTERN "*.h" - PATTERN "recordable.h" EXCLUDE) +if(OPENTELEMETRY_INSTALL) + install( + TARGETS opentelemetry_exporter_jaeger_trace + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + install( + DIRECTORY include/opentelemetry/exporters/jaeger + DESTINATION include/opentelemetry/exporters + FILES_MATCHING + PATTERN "*.h" + PATTERN "recordable.h" EXCLUDE) +endif() if(BUILD_TESTING) add_definitions(-DGTEST_LINKED_AS_SHARED_LIBRARY=1) diff --git a/exporters/jaeger/README.md b/exporters/jaeger/README.md index d4fa3b45b8..2a795596a4 100644 --- a/exporters/jaeger/README.md +++ b/exporters/jaeger/README.md @@ -1,5 +1,11 @@ # Jaeger Exporter for OpenTelemetry C++ +## DEPRECATED + +The Jaeger Exporter is deprecated, and will be removed in a future release. + +See [DEPRECATED](../../DEPRECATED.md) for details. + ## Prerequisite * [Get Jaeger](https://www.jaegertracing.io/docs/getting-started/) and run diff --git a/exporters/jaeger/include/opentelemetry/exporters/jaeger/jaeger_exporter.h b/exporters/jaeger/include/opentelemetry/exporters/jaeger/jaeger_exporter.h index a55aca29df..eac6dc6940 100644 --- a/exporters/jaeger/include/opentelemetry/exporters/jaeger/jaeger_exporter.h +++ b/exporters/jaeger/include/opentelemetry/exporters/jaeger/jaeger_exporter.h @@ -3,6 +3,10 @@ #pragma once +#ifdef OPENTELEMETRY_NO_DEPRECATED_CODE +# error "header is deprecated." +#endif + #include #include #include @@ -16,7 +20,7 @@ namespace jaeger class ThriftSender; -class JaegerExporter final : public opentelemetry::sdk::trace::SpanExporter +class OPENTELEMETRY_DEPRECATED JaegerExporter final : public opentelemetry::sdk::trace::SpanExporter { public: /** @@ -43,6 +47,14 @@ class JaegerExporter final : public opentelemetry::sdk::trace::SpanExporter const nostd::span> &spans) noexcept override; + /** + * Force flush the exporter. + * @param timeout an option timeout, default to max. + * @return return true when all data are exported, and false when timeout + */ + bool ForceFlush( + std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override; + /** * Shutdown the exporter. * @param timeout an option timeout, default to max. diff --git a/exporters/jaeger/include/opentelemetry/exporters/jaeger/jaeger_exporter_factory.h b/exporters/jaeger/include/opentelemetry/exporters/jaeger/jaeger_exporter_factory.h index 7d43093f41..e8f4f75eb0 100644 --- a/exporters/jaeger/include/opentelemetry/exporters/jaeger/jaeger_exporter_factory.h +++ b/exporters/jaeger/include/opentelemetry/exporters/jaeger/jaeger_exporter_factory.h @@ -3,6 +3,10 @@ #pragma once +#ifdef OPENTELEMETRY_NO_DEPRECATED_CODE +# error "header is deprecated." +#endif + #include #include @@ -15,7 +19,7 @@ namespace jaeger /** * Factory class for JaegerExporter. */ -class JaegerExporterFactory +class OPENTELEMETRY_DEPRECATED JaegerExporterFactory { public: /** diff --git a/exporters/jaeger/include/opentelemetry/exporters/jaeger/jaeger_exporter_options.h b/exporters/jaeger/include/opentelemetry/exporters/jaeger/jaeger_exporter_options.h index d4f509e0d9..8250f09aab 100644 --- a/exporters/jaeger/include/opentelemetry/exporters/jaeger/jaeger_exporter_options.h +++ b/exporters/jaeger/include/opentelemetry/exporters/jaeger/jaeger_exporter_options.h @@ -3,6 +3,12 @@ #pragma once +#include + +#ifdef OPENTELEMETRY_NO_DEPRECATED_CODE +# error "header is deprecated." +#endif + #include OPENTELEMETRY_BEGIN_NAMESPACE @@ -21,7 +27,7 @@ enum class TransportFormat /** * Struct to hold Jaeger exporter options. */ -struct JaegerExporterOptions +struct OPENTELEMETRY_DEPRECATED JaegerExporterOptions { TransportFormat transport_format = TransportFormat::kThriftUdpCompact; std::string endpoint = "localhost"; diff --git a/exporters/jaeger/src/THttpTransport.cc b/exporters/jaeger/src/THttpTransport.cc index cbb1b65cb2..db2c8a0cd2 100644 --- a/exporters/jaeger/src/THttpTransport.cc +++ b/exporters/jaeger/src/THttpTransport.cc @@ -39,7 +39,7 @@ void THttpTransport::write(const uint8_t *buf, uint32_t len) bool THttpTransport::sendSpans() { - auto result = client->Post(endpoint, request_buffer, headers); + auto result = client->PostNoSsl(endpoint, request_buffer, headers); request_buffer.clear(); // TODO: Add logging once global log handling is available. diff --git a/exporters/jaeger/src/http_transport.h b/exporters/jaeger/src/http_transport.h index 8f5c9c0571..8748ae53a2 100644 --- a/exporters/jaeger/src/http_transport.h +++ b/exporters/jaeger/src/http_transport.h @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + #pragma once #include "THttpTransport.h" diff --git a/exporters/jaeger/src/jaeger_exporter.cc b/exporters/jaeger/src/jaeger_exporter.cc index 8e9e75bd73..7f413caf30 100644 --- a/exporters/jaeger/src/jaeger_exporter.cc +++ b/exporters/jaeger/src/jaeger_exporter.cc @@ -98,6 +98,11 @@ void JaegerExporter::InitializeEndpoint() assert(false); } +bool JaegerExporter::ForceFlush(std::chrono::microseconds /* timeout */) noexcept +{ + return true; +} + bool JaegerExporter::Shutdown(std::chrono::microseconds /* timeout */) noexcept { const std::lock_guard locked(lock_); diff --git a/exporters/memory/BUILD b/exporters/memory/BUILD index daa0c662ff..a65066480c 100644 --- a/exporters/memory/BUILD +++ b/exporters/memory/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + package(default_visibility = ["//visibility:public"]) cc_library( diff --git a/exporters/memory/CMakeLists.txt b/exporters/memory/CMakeLists.txt index 7fb357d73a..36ddca5ac5 100644 --- a/exporters/memory/CMakeLists.txt +++ b/exporters/memory/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + add_library(opentelemetry_exporter_in_memory src/in_memory_span_exporter_factory.cc) @@ -12,18 +15,20 @@ set_target_properties(opentelemetry_exporter_in_memory target_link_libraries(opentelemetry_exporter_in_memory PUBLIC opentelemetry_trace) -install( - TARGETS opentelemetry_exporter_in_memory - EXPORT "${PROJECT_NAME}-target" - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - -install( - DIRECTORY include/opentelemetry/exporters/memory - DESTINATION include/opentelemetry/exporters - FILES_MATCHING - PATTERN "*.h") +if(OPENTELEMETRY_INSTALL) + install( + TARGETS opentelemetry_exporter_in_memory + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + install( + DIRECTORY include/opentelemetry/exporters/memory + DESTINATION include/opentelemetry/exporters + FILES_MATCHING + PATTERN "*.h") +endif() if(BUILD_TESTING) add_executable(in_memory_span_data_test test/in_memory_span_data_test.cc) diff --git a/exporters/ostream/BUILD b/exporters/ostream/BUILD index eebb332628..a80e84a024 100644 --- a/exporters/ostream/BUILD +++ b/exporters/ostream/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + package(default_visibility = ["//visibility:public"]) cc_library( diff --git a/exporters/ostream/CMakeLists.txt b/exporters/ostream/CMakeLists.txt index c491aa8a1f..22396c58bd 100644 --- a/exporters/ostream/CMakeLists.txt +++ b/exporters/ostream/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + add_library(opentelemetry_exporter_ostream_span src/span_exporter.cc src/span_exporter_factory.cc) @@ -11,18 +14,20 @@ target_include_directories( target_link_libraries(opentelemetry_exporter_ostream_span PUBLIC opentelemetry_trace) -install( - TARGETS opentelemetry_exporter_ostream_span - EXPORT "${PROJECT_NAME}-target" - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +if(OPENTELEMETRY_INSTALL) + install( + TARGETS opentelemetry_exporter_ostream_span + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) -install( - DIRECTORY include/opentelemetry/exporters/ostream - DESTINATION include/opentelemetry/exporters - PATTERN "*.h" - PATTERN "log_Exporter.h" EXCLUDE) + install( + DIRECTORY include/opentelemetry/exporters/ostream + DESTINATION include/opentelemetry/exporters + PATTERN "*.h" + PATTERN "log_Exporter.h" EXCLUDE) +endif() if(BUILD_TESTING) add_executable(ostream_span_test test/ostream_span_test.cc) @@ -42,16 +47,20 @@ target_include_directories( PUBLIC "$") target_link_libraries(opentelemetry_exporter_ostream_metrics PUBLIC opentelemetry_metrics opentelemetry_resources) -install( - TARGETS opentelemetry_exporter_ostream_metrics - EXPORT "${PROJECT_NAME}-target" - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) -install( - DIRECTORY include/opentelemetry/exporters/ostream - DESTINATION include/opentelemetry/exporters - PATTERN "metric_exporter.h") + +if(OPENTELEMETRY_INSTALL) + install( + TARGETS opentelemetry_exporter_ostream_metrics + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install( + DIRECTORY include/opentelemetry/exporters/ostream + DESTINATION include/opentelemetry/exporters + PATTERN "metric_exporter.h") +endif() + if(BUILD_TESTING) add_executable(ostream_metric_test test/ostream_metric_test.cc) target_link_libraries( @@ -72,16 +81,20 @@ if(WITH_LOGS_PREVIEW) PUBLIC "$") target_link_libraries(opentelemetry_exporter_ostream_logs PUBLIC opentelemetry_logs) - install( - TARGETS opentelemetry_exporter_ostream_logs - EXPORT "${PROJECT_NAME}-target" - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - install( - DIRECTORY include/opentelemetry/exporters/ostream - DESTINATION include/opentelemetry/exporters - PATTERN "log_record_exporter.h") + + if(OPENTELEMETRY_INSTALL) + install( + TARGETS opentelemetry_exporter_ostream_logs + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install( + DIRECTORY include/opentelemetry/exporters/ostream + DESTINATION include/opentelemetry/exporters + PATTERN "log_record_exporter.h") + endif() + if(BUILD_TESTING) add_executable(ostream_log_test test/ostream_log_test.cc) target_link_libraries(ostream_log_test ${GTEST_BOTH_LIBRARIES} diff --git a/exporters/ostream/include/opentelemetry/exporters/ostream/log_record_exporter.h b/exporters/ostream/include/opentelemetry/exporters/ostream/log_record_exporter.h index f5e400946f..34806bd200 100644 --- a/exporters/ostream/include/opentelemetry/exporters/ostream/log_record_exporter.h +++ b/exporters/ostream/include/opentelemetry/exporters/ostream/log_record_exporter.h @@ -39,6 +39,14 @@ class OStreamLogRecordExporter final : public opentelemetry::sdk::logs::LogRecor const opentelemetry::nostd::span> &records) noexcept override; + /** + * Force flush the exporter. + * @param timeout an option timeout, default to max. + * @return return true when all data are exported, and false when timeout + */ + bool ForceFlush( + std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override; + /** * Marks the OStream Log Exporter as shut down. */ diff --git a/exporters/ostream/include/opentelemetry/exporters/ostream/span_exporter.h b/exporters/ostream/include/opentelemetry/exporters/ostream/span_exporter.h index 985e05715a..baa4e860b1 100644 --- a/exporters/ostream/include/opentelemetry/exporters/ostream/span_exporter.h +++ b/exporters/ostream/include/opentelemetry/exporters/ostream/span_exporter.h @@ -38,6 +38,14 @@ class OStreamSpanExporter final : public opentelemetry::sdk::trace::SpanExporter const opentelemetry::nostd::span> &spans) noexcept override; + /** + * Force flush the exporter. + * @param timeout an option timeout, default to max. + * @return return true when all data are exported, and false when timeout + */ + bool ForceFlush( + std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override; + bool Shutdown( std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override; diff --git a/exporters/ostream/include/opentelemetry/exporters/ostream/span_exporter_factory.h b/exporters/ostream/include/opentelemetry/exporters/ostream/span_exporter_factory.h index c7216410b9..79ba3b06d4 100644 --- a/exporters/ostream/include/opentelemetry/exporters/ostream/span_exporter_factory.h +++ b/exporters/ostream/include/opentelemetry/exporters/ostream/span_exporter_factory.h @@ -25,7 +25,7 @@ namespace trace /** * Factory class for OStreamSpanExporter. */ -class OStreamSpanExporterFactory +class OPENTELEMETRY_EXPORT OStreamSpanExporterFactory { public: /** diff --git a/exporters/ostream/src/log_record_exporter.cc b/exporters/ostream/src/log_record_exporter.cc index ca751b810e..751de71e2c 100644 --- a/exporters/ostream/src/log_record_exporter.cc +++ b/exporters/ostream/src/log_record_exporter.cc @@ -88,26 +88,37 @@ sdk::common::ExportResult OStreamLogRecordExporter::Export( sout_ << " body : "; opentelemetry::exporter::ostream_common::print_value(log_record->GetBody(), sout_); - sout_ << "\n"; + sout_ << "\n resource : "; + printAttributes(log_record->GetResource().GetAttributes(), "\n "); - sout_ << " resource : "; - printAttributes(log_record->GetResource().GetAttributes()); + sout_ << "\n attributes : "; - sout_ << "\n" - << " attributes : "; - - printAttributes(log_record->GetAttributes()); + printAttributes(log_record->GetAttributes(), "\n "); sout_ << "\n" << " trace_id : " << std::string(trace_id, trace_id_len) << "\n" << " span_id : " << std::string(span_id, span_id__len) << "\n" << " trace_flags : " << std::string(trace_flags, trace_flags_len) << "\n" - << "}\n"; + << " scope : \n" + << " name : " << log_record->GetInstrumentationScope().GetName() << "\n" + << " version : " << log_record->GetInstrumentationScope().GetVersion() << "\n" + << " schema_url : " << log_record->GetInstrumentationScope().GetSchemaURL() + << "\n" + << " attributes : "; + + printAttributes(log_record->GetInstrumentationScope().GetAttributes(), "\n "); + sout_ << "\n}\n"; } return sdk::common::ExportResult::kSuccess; } +bool OStreamLogRecordExporter::ForceFlush(std::chrono::microseconds /* timeout */) noexcept +{ + sout_.flush(); + return true; +} + bool OStreamLogRecordExporter::Shutdown(std::chrono::microseconds) noexcept { const std::lock_guard locked(lock_); diff --git a/exporters/ostream/src/span_exporter.cc b/exporters/ostream/src/span_exporter.cc index 79be26b311..6a88c32235 100644 --- a/exporters/ostream/src/span_exporter.cc +++ b/exporters/ostream/src/span_exporter.cc @@ -98,6 +98,12 @@ sdk::common::ExportResult OStreamSpanExporter::Export( return sdk::common::ExportResult::kSuccess; } +bool OStreamSpanExporter::ForceFlush(std::chrono::microseconds /* timeout */) noexcept +{ + sout_.flush(); + return true; +} + bool OStreamSpanExporter::Shutdown(std::chrono::microseconds /* timeout */) noexcept { const std::lock_guard locked(lock_); diff --git a/exporters/ostream/test/ostream_log_test.cc b/exporters/ostream/test/ostream_log_test.cc index e247f06038..95cdb69380 100644 --- a/exporters/ostream/test/ostream_log_test.cc +++ b/exporters/ostream/test/ostream_log_test.cc @@ -26,6 +26,19 @@ namespace exporter namespace logs { +namespace +{ +static opentelemetry::sdk::instrumentationscope::InstrumentationScope GetTestInstrumentationScope() +{ + opentelemetry::sdk::instrumentationscope::InstrumentationScope result = + opentelemetry::sdk::logs::ReadableLogRecord::GetDefaultInstrumentationScope(); + + result.SetAttribute("scope.attr.key", "scope.attr.value"); + + return result; +} +} // namespace + // Test that when OStream Log exporter is shutdown, no logs should be sent to stream TEST(OStreamLogRecordExporter, Shutdown) { @@ -71,6 +84,9 @@ TEST(OstreamLogExporter, DefaultLogRecordToCout) // Pass a default recordable created by the exporter to be exported auto log_record = exporter->MakeRecordable(); + opentelemetry::sdk::instrumentationscope::InstrumentationScope instrumentation_scope = + GetTestInstrumentationScope(); + log_record->SetInstrumentationScope(instrumentation_scope); exporter->Export(nostd::span>(&log_record, 1)); // Restore cout's original stringstream @@ -83,18 +99,30 @@ TEST(OstreamLogExporter, DefaultLogRecordToCout) " severity_text : INVALID\n" " body : \n", " resource : \n", - "telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n", - "telemetry.sdk.name: opentelemetry\n", - "telemetry.sdk.language: cpp\n", - " attributes : \n" - " trace_id : 00000000000000000000000000000000\n" - " span_id : 0000000000000000\n" - " trace_flags : 00\n" + " telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n", + " telemetry.sdk.name: opentelemetry\n", + " telemetry.sdk.language: cpp\n", + " attributes : \n", + " trace_id : 00000000000000000000000000000000\n", + " span_id : 0000000000000000\n", + " trace_flags : 00\n", + " scope : \n", + " name : otel-cpp\n", + " version : " OPENTELEMETRY_SDK_VERSION "\n", + " schema_url : https://opentelemetry.io/schemas/1.15.0\n", + " attributes : \n", + " scope.attr.key: scope.attr.value\n", "}\n"}; + std::string ostream_output = output.str(); for (auto &expected : expected_output) { - ASSERT_NE(output.str().find(expected), std::string::npos); + std::string::size_type result = ostream_output.find(expected); + if (result == std::string::npos) + { + std::cout << "Can not find: \"" << expected << "\" in\n" << ostream_output << std::endl; + } + ASSERT_NE(result, std::string::npos); } } @@ -122,6 +150,10 @@ TEST(OStreamLogRecordExporter, SimpleLogToCout) ->SetSeverity(logs_api::Severity::kTrace); // kTrace has enum value of 1 static_cast(record.get())->SetBody("Message"); + opentelemetry::sdk::instrumentationscope::InstrumentationScope instrumentation_scope = + GetTestInstrumentationScope(); + record->SetInstrumentationScope(instrumentation_scope); + // Log a record to cout exporter->Export(nostd::span>(&record, 1)); @@ -140,18 +172,30 @@ TEST(OStreamLogRecordExporter, SimpleLogToCout) " severity_text : TRACE\n" " body : Message\n", " resource : \n", - "telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n", - "telemetry.sdk.name: opentelemetry\n", - "telemetry.sdk.language: cpp\n", - " attributes : \n" - " trace_id : 00000000000000000000000000000000\n" - " span_id : 0000000000000000\n" - " trace_flags : 00\n" + " telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n", + " telemetry.sdk.name: opentelemetry\n", + " telemetry.sdk.language: cpp\n", + " attributes : \n", + " trace_id : 00000000000000000000000000000000\n", + " span_id : 0000000000000000\n", + " trace_flags : 00\n", + " scope : \n", + " name : otel-cpp\n", + " version : " OPENTELEMETRY_SDK_VERSION "\n", + " schema_url : https://opentelemetry.io/schemas/1.15.0\n", + " attributes : \n", + " scope.attr.key: scope.attr.value\n", "}\n"}; + std::string ostream_output = output.str(); for (auto &expected : expected_output) { - ASSERT_NE(output.str().find(expected), std::string::npos); + std::string::size_type result = ostream_output.find(expected); + if (result == std::string::npos) + { + std::cout << "Can not find: \"" << expected << "\" in\n" << ostream_output << std::endl; + } + ASSERT_NE(result, std::string::npos); } } @@ -180,6 +224,10 @@ TEST(OStreamLogRecordExporter, LogWithStringAttributesToCerr) // Set attributes to this log record of type static_cast(record.get())->SetAttribute("a", true); + opentelemetry::sdk::instrumentationscope::InstrumentationScope instrumentation_scope = + GetTestInstrumentationScope(); + record->SetInstrumentationScope(instrumentation_scope); + // Log record to cerr exporter->Export(nostd::span>(&record, 1)); @@ -193,21 +241,33 @@ TEST(OStreamLogRecordExporter, LogWithStringAttributesToCerr) " severity_text : INVALID\n" " body : \n", " resource : \n", - "telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n", - "telemetry.sdk.name: opentelemetry\n", - "telemetry.sdk.language: cpp\n", - "service.name: unknown_service\n", - "key1: val1\n", + " telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n", + " telemetry.sdk.name: opentelemetry\n", + " telemetry.sdk.language: cpp\n", + " service.name: unknown_service\n", + " key1: val1\n", " attributes : \n", - "\ta: 1\n", - " trace_id : 00000000000000000000000000000000\n" - " span_id : 0000000000000000\n" - " trace_flags : 00\n" + " a: 1\n", + " trace_id : 00000000000000000000000000000000\n", + " span_id : 0000000000000000\n", + " trace_flags : 00\n", + " scope : \n", + " name : otel-cpp\n", + " version : " OPENTELEMETRY_SDK_VERSION "\n", + " schema_url : https://opentelemetry.io/schemas/1.15.0\n", + " attributes : \n", + " scope.attr.key: scope.attr.value\n", "}\n"}; + std::string ostream_output = stdcerrOutput.str(); for (auto &expected : expected_output) { - ASSERT_NE(stdcerrOutput.str().find(expected), std::string::npos); + std::string::size_type result = ostream_output.find(expected); + if (result == std::string::npos) + { + std::cout << "Can not find: \"" << expected << "\" in\n" << ostream_output << std::endl; + } + ASSERT_NE(result, std::string::npos); } } @@ -243,6 +303,10 @@ TEST(OStreamLogRecordExporter, LogWithVariantTypesToClog) static_cast(record.get()) ->SetAttribute("attr1", nostd::span{array.data(), array.size()}); + opentelemetry::sdk::instrumentationscope::InstrumentationScope instrumentation_scope = + GetTestInstrumentationScope(); + record->SetInstrumentationScope(instrumentation_scope); + // Log a record to clog exporter->Export(nostd::span>(&record, 1)); @@ -256,21 +320,33 @@ TEST(OStreamLogRecordExporter, LogWithVariantTypesToClog) " severity_text : INVALID\n" " body : \n", " resource : \n", - "service.name: unknown_service\n", - "telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n", - "telemetry.sdk.name: opentelemetry\n", - "telemetry.sdk.language: cpp\n", - "res1: [1,2,3]\n", - "attributes : \n", - "\tattr1: [0,1,0]\n" - " trace_id : 00000000000000000000000000000000\n" - " span_id : 0000000000000000\n" - " trace_flags : 00\n" + " service.name: unknown_service\n", + " telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n", + " telemetry.sdk.name: opentelemetry\n", + " telemetry.sdk.language: cpp\n", + " res1: [1,2,3]\n", + " attributes : \n", + " attr1: [0,1,0]\n", + " trace_id : 00000000000000000000000000000000\n", + " span_id : 0000000000000000\n", + " trace_flags : 00\n", + " scope : \n", + " name : otel-cpp\n", + " version : " OPENTELEMETRY_SDK_VERSION "\n", + " schema_url : https://opentelemetry.io/schemas/1.15.0\n", + " attributes : \n", + " scope.attr.key: scope.attr.value\n", "}\n"}; + std::string ostream_output = stdclogOutput.str(); for (auto &expected : expected_output) { - ASSERT_NE(stdclogOutput.str().find(expected), std::string::npos); + std::string::size_type result = ostream_output.find(expected); + if (result == std::string::npos) + { + std::cout << "Can not find: \"" << expected << "\" in\n" << ostream_output << std::endl; + } + ASSERT_NE(result, std::string::npos); } } @@ -291,7 +367,8 @@ TEST(OStreamLogRecordExporter, IntegrationTest) logs_api::Provider::SetLoggerProvider(provider); const std::string schema_url{"https://opentelemetry.io/schemas/1.11.0"}; auto logger = logs_api::Provider::GetLoggerProvider()->GetLogger( - "Logger", "", "opentelelemtry_library", "", schema_url); + "Logger", "opentelelemtry_library", OPENTELEMETRY_SDK_VERSION, schema_url, true, + {{"scope.attr.key", 123}}); // Back up cout's streambuf std::streambuf *original = std::cout.rdbuf(); @@ -302,7 +379,7 @@ TEST(OStreamLogRecordExporter, IntegrationTest) // Write a log to ostream exporter common::SystemTimestamp now(std::chrono::system_clock::now()); - logger->Log(logs_api::Severity::kDebug, "Hello", {}, {}, {}, {}, now); + logger->EmitLogRecord(logs_api::Severity::kDebug, "Hello", now); // Restore cout's original streambuf std::cout.rdbuf(original); @@ -316,19 +393,31 @@ TEST(OStreamLogRecordExporter, IntegrationTest) " severity_text : DEBUG\n" " body : Hello\n", " resource : \n", - "telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n", - "service.name: unknown_service\n", - "telemetry.sdk.name: opentelemetry\n", - "telemetry.sdk.language: cpp\n", - " attributes : \n" - " trace_id : 00000000000000000000000000000000\n" - " span_id : 0000000000000000\n" - " trace_flags : 00\n" + " telemetry.sdk.version: " OPENTELEMETRY_VERSION "\n", + " service.name: unknown_service\n", + " telemetry.sdk.name: opentelemetry\n", + " telemetry.sdk.language: cpp\n", + " attributes : \n", + " trace_id : 00000000000000000000000000000000\n", + " span_id : 0000000000000000\n", + " trace_flags : 00\n", + " scope : \n", + " name : opentelelemtry_library\n", + " version : " OPENTELEMETRY_SDK_VERSION "\n", + " schema_url : https://opentelemetry.io/schemas/1.11.0\n", + " attributes : \n", + " scope.attr.key: 123\n", "}\n"}; + std::string ostream_output = stdcoutOutput.str(); for (auto &expected : expected_output) { - ASSERT_NE(stdcoutOutput.str().find(expected), std::string::npos); + std::string::size_type result = ostream_output.find(expected); + if (result == std::string::npos) + { + std::cout << "Can not find: \"" << expected << "\" in\n" << ostream_output << std::endl; + } + ASSERT_NE(result, std::string::npos); } } diff --git a/exporters/ostream/test/ostream_metric_test.cc b/exporters/ostream/test/ostream_metric_test.cc index 9aca741d67..cb4a8a3ab4 100644 --- a/exporters/ostream/test/ostream_metric_test.cc +++ b/exporters/ostream/test/ostream_metric_test.cc @@ -97,14 +97,14 @@ TEST(OStreamMetricsExporter, ExportHistogramPointData) std::unique_ptr(new exportermetrics::OStreamMetricExporter); metric_sdk::HistogramPointData histogram_point_data{}; - histogram_point_data.boundaries_ = std::list{10.1, 20.2, 30.2}; + histogram_point_data.boundaries_ = std::vector{10.1, 20.2, 30.2}; histogram_point_data.count_ = 3; histogram_point_data.counts_ = {200, 300, 400, 500}; histogram_point_data.sum_ = 900.5; histogram_point_data.min_ = 1.8; histogram_point_data.max_ = 12.0; metric_sdk::HistogramPointData histogram_point_data2{}; - histogram_point_data2.boundaries_ = std::list{10.0, 20.0, 30.0}; + histogram_point_data2.boundaries_ = std::vector{10.0, 20.0, 30.0}; histogram_point_data2.count_ = 3; histogram_point_data2.counts_ = {200, 300, 400, 500}; histogram_point_data2.sum_ = (int64_t)900; diff --git a/exporters/otlp/BUILD b/exporters/otlp/BUILD index a75188e673..98ae13ebb1 100644 --- a/exporters/otlp/BUILD +++ b/exporters/otlp/BUILD @@ -1,16 +1,5 @@ -# 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. +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 package(default_visibility = ["//visibility:public"]) @@ -19,6 +8,7 @@ load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark") cc_library( name = "otlp_recordable", srcs = [ + "src/otlp_environment.cc", "src/otlp_log_recordable.cc", "src/otlp_metric_utils.cc", "src/otlp_populate_attribute_utils.cc", @@ -26,6 +16,7 @@ cc_library( "src/otlp_recordable_utils.cc", ], hdrs = [ + "include/opentelemetry/exporters/otlp/otlp_environment.h", "include/opentelemetry/exporters/otlp/otlp_log_recordable.h", "include/opentelemetry/exporters/otlp/otlp_metric_utils.h", "include/opentelemetry/exporters/otlp/otlp_populate_attribute_utils.h", diff --git a/exporters/otlp/CMakeLists.txt b/exporters/otlp/CMakeLists.txt index 88f526171b..c31f5619f2 100644 --- a/exporters/otlp/CMakeLists.txt +++ b/exporters/otlp/CMakeLists.txt @@ -1,6 +1,9 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + add_library( opentelemetry_otlp_recordable - src/otlp_log_recordable.cc src/otlp_recordable.cc + src/otlp_environment.cc src/otlp_log_recordable.cc src/otlp_recordable.cc src/otlp_populate_attribute_utils.cc src/otlp_recordable_utils.cc src/otlp_metric_utils.cc) set_target_properties(opentelemetry_otlp_recordable PROPERTIES EXPORT_NAME @@ -94,7 +97,6 @@ if(WITH_OTLP_GRPC) endif() if(WITH_OTLP_HTTP) - find_package(CURL REQUIRED) add_library(opentelemetry_exporter_otlp_http_client src/otlp_http_client.cc) set_target_properties(opentelemetry_exporter_otlp_http_client PROPERTIES EXPORT_NAME otlp_http_client) @@ -160,18 +162,20 @@ if(WITH_OTLP_HTTP) opentelemetry_exporter_otlp_http_metric) endif() -install( - TARGETS ${OPENTELEMETRY_OTLP_TARGETS} - EXPORT "${PROJECT_NAME}-target" - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - -install( - DIRECTORY include/opentelemetry/exporters/otlp - DESTINATION include/opentelemetry/exporters - FILES_MATCHING - PATTERN "*.h") +if(OPENTELEMETRY_INSTALL) + install( + TARGETS ${OPENTELEMETRY_OTLP_TARGETS} + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + install( + DIRECTORY include/opentelemetry/exporters/otlp + DESTINATION include/opentelemetry/exporters + FILES_MATCHING + PATTERN "*.h") +endif() if(BUILD_TESTING) add_executable(otlp_recordable_test test/otlp_recordable_test.cc) diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_environment.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_environment.h index 27bd378b7c..3be133b4cf 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_environment.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_environment.h @@ -22,346 +22,132 @@ namespace exporter namespace otlp { -inline const std::string GetOtlpDefaultUserAgent() +inline std::string GetOtlpDefaultUserAgent() { return "OTel-OTLP-Exporter-Cpp/" OPENTELEMETRY_SDK_VERSION; } -inline const std::string GetOtlpDefaultGrpcEndpoint() -{ - constexpr char kOtlpTracesEndpointEnv[] = "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"; - constexpr char kOtlpEndpointEnv[] = "OTEL_EXPORTER_OTLP_ENDPOINT"; - constexpr char kOtlpEndpointDefault[] = "http://localhost:4317"; +std::string GetOtlpDefaultGrpcTracesEndpoint(); +std::string GetOtlpDefaultGrpcMetricsEndpoint(); +std::string GetOtlpDefaultGrpcLogsEndpoint(); - auto endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTracesEndpointEnv); - if (endpoint.empty()) - { - endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpEndpointEnv); - } - return endpoint.size() ? endpoint : kOtlpEndpointDefault; -} - -inline const std::string GetOtlpDefaultHttpEndpoint() +// Compatibility with OTELCPP 1.8.2 +inline std::string GetOtlpDefaultGrpcEndpoint() { - constexpr char kOtlpTracesEndpointEnv[] = "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"; - constexpr char kOtlpEndpointEnv[] = "OTEL_EXPORTER_OTLP_ENDPOINT"; - constexpr char kOtlpEndpointDefault[] = "http://localhost:4318/v1/traces"; - - auto endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTracesEndpointEnv); - if (endpoint.empty()) - { - endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpEndpointEnv); - if (!endpoint.empty()) - { - endpoint += "/v1/traces"; - } - } - return endpoint.size() ? endpoint : kOtlpEndpointDefault; + return GetOtlpDefaultGrpcTracesEndpoint(); } -inline bool GetOtlpDefaultIsSslEnable() -{ - constexpr char kOtlpTracesIsSslEnableEnv[] = "OTEL_EXPORTER_OTLP_TRACES_SSL_ENABLE"; - constexpr char kOtlpIsSslEnableEnv[] = "OTEL_EXPORTER_OTLP_SSL_ENABLE"; +std::string GetOtlpDefaultHttpTracesEndpoint(); +std::string GetOtlpDefaultHttpMetricsEndpoint(); +std::string GetOtlpDefaultHttpLogsEndpoint(); - auto ssl_enable = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTracesIsSslEnableEnv); - if (ssl_enable.empty()) - { - ssl_enable = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpIsSslEnableEnv); - } - if (ssl_enable == "True" || ssl_enable == "TRUE" || ssl_enable == "true" || ssl_enable == "1") - { - return true; - } - return false; -} - -inline const std::string GetOtlpDefaultSslCertificatePath() +// Compatibility with OTELCPP 1.8.2 +inline std::string GetOtlpDefaultHttpEndpoint() { - constexpr char kOtlpTracesSslCertificate[] = "OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE"; - constexpr char kOtlpSslCertificate[] = "OTEL_EXPORTER_OTLP_CERTIFICATE"; - auto ssl_cert_path = - opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTracesSslCertificate); - if (ssl_cert_path.empty()) - { - ssl_cert_path = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpSslCertificate); - } - return ssl_cert_path.size() ? ssl_cert_path : ""; + return GetOtlpDefaultHttpTracesEndpoint(); } -inline const std::string GetOtlpDefaultSslCertificateString() +// Compatibility with OTELCPP 1.8.2 +inline std::string GetOtlpDefaultMetricsEndpoint() { - constexpr char kOtlpTracesSslCertificateString[] = "OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE_STRING"; - constexpr char kOtlpSslCertificateString[] = "OTEL_EXPORTER_OTLP_CERTIFICATE_STRING"; - auto ssl_cert = - opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTracesSslCertificateString); - if (ssl_cert.empty()) - { - ssl_cert = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpSslCertificateString); - } - return ssl_cert.size() ? ssl_cert : ""; + return GetOtlpDefaultHttpMetricsEndpoint(); } -inline const std::chrono::system_clock::duration GetOtlpTimeoutFromString(const char *input) -{ - if (nullptr == input || 0 == *input) - { - return std::chrono::duration_cast( - std::chrono::seconds{10}); - } - - std::chrono::system_clock::duration::rep result = 0; - // Skip spaces - for (; *input && (' ' == *input || '\t' == *input || '\r' == *input || '\n' == *input); ++input) - ; - - for (; *input && (*input >= '0' && *input <= '9'); ++input) - { - result = result * 10 + (*input - '0'); - } - - opentelemetry::nostd::string_view unit{input}; - if ("ns" == unit) - { - return std::chrono::duration_cast( - std::chrono::nanoseconds{result}); - } - else if ("us" == unit) - { - return std::chrono::duration_cast( - std::chrono::microseconds{result}); - } - else if ("ms" == unit) - { - return std::chrono::duration_cast( - std::chrono::milliseconds{result}); - } - else if ("m" == unit) - { - return std::chrono::duration_cast( - std::chrono::minutes{result}); - } - else if ("h" == unit) - { - return std::chrono::duration_cast( - std::chrono::hours{result}); - } - else - { - return std::chrono::duration_cast( - std::chrono::seconds{result}); - } -} +bool GetOtlpDefaultGrpcTracesIsInsecure(); +bool GetOtlpDefaultGrpcMetricsIsInsecure(); +bool GetOtlpDefaultGrpcLogsIsInsecure(); -inline const std::chrono::system_clock::duration GetOtlpDefaultTimeout() +// Compatibility with OTELCPP 1.8.2 +inline bool GetOtlpDefaultIsSslEnable() { - constexpr char kOtlpTracesTimeoutEnv[] = "OTEL_EXPORTER_OTLP_TRACES_TIMEOUT"; - constexpr char kOtlpTimeoutEnv[] = "OTEL_EXPORTER_OTLP_TIMEOUT"; - - auto timeout = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTracesTimeoutEnv); - if (timeout.empty()) - { - timeout = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTimeoutEnv); - } - return GetOtlpTimeoutFromString(timeout.c_str()); + return (!GetOtlpDefaultGrpcTracesIsInsecure()); } -struct cmp_ic -{ - bool operator()(const std::string &s1, const std::string &s2) const - { - return std::lexicographical_compare( - s1.begin(), s1.end(), s2.begin(), s2.end(), - [](char c1, char c2) { return ::tolower(c1) < ::tolower(c2); }); - } -}; -using OtlpHeaders = std::multimap; +std::string GetOtlpDefaultTracesSslCertificatePath(); +std::string GetOtlpDefaultMetricsSslCertificatePath(); +std::string GetOtlpDefaultLogsSslCertificatePath(); -inline void DumpOtlpHeaders(OtlpHeaders &output, - const char *env_var_name, - std::unordered_set &remove_cache) +// Compatibility with OTELCPP 1.8.2 +inline std::string GetOtlpDefaultSslCertificatePath() { - auto value = opentelemetry::sdk::common::GetEnvironmentVariable(env_var_name); - if (value.empty()) - { - return; - } - - opentelemetry::common::KeyValueStringTokenizer tokenizer{value}; - opentelemetry::nostd::string_view header_key; - opentelemetry::nostd::string_view header_value; - bool header_valid = true; - - while (tokenizer.next(header_valid, header_key, header_value)) - { - if (header_valid) - { - std::string key = static_cast(header_key); - if (remove_cache.end() == remove_cache.find(key)) - { - remove_cache.insert(key); - auto range = output.equal_range(key); - if (range.first != range.second) - { - output.erase(range.first, range.second); - } - } - - output.emplace(std::make_pair(std::move(key), static_cast(header_value))); - } - } + return GetOtlpDefaultTracesSslCertificatePath(); } -inline OtlpHeaders GetOtlpDefaultHeaders() -{ - constexpr char kOtlpTracesHeadersEnv[] = "OTEL_EXPORTER_OTLP_TRACES_HEADERS"; - constexpr char kOtlpHeadersEnv[] = "OTEL_EXPORTER_OTLP_HEADERS"; - - OtlpHeaders result; - std::unordered_set trace_remove_cache; - DumpOtlpHeaders(result, kOtlpHeadersEnv, trace_remove_cache); - - trace_remove_cache.clear(); - DumpOtlpHeaders(result, kOtlpTracesHeadersEnv, trace_remove_cache); - - return result; -} +std::string GetOtlpDefaultTracesSslCertificateString(); +std::string GetOtlpDefaultMetricsSslCertificateString(); +std::string GetOtlpDefaultLogsSslCertificateString(); -inline const std::string GetOtlpDefaultHttpLogEndpoint() +// Compatibility with OTELCPP 1.8.2 +inline std::string GetOtlpDefaultSslCertificateString() { - constexpr char kOtlpLogsEndpointEnv[] = "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT"; - constexpr char kOtlpEndpointEnv[] = "OTEL_EXPORTER_OTLP_ENDPOINT"; - constexpr char kOtlpEndpointDefault[] = "http://localhost:4318/v1/logs"; - - auto endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpLogsEndpointEnv); - if (endpoint.empty()) - { - endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpEndpointEnv); - if (!endpoint.empty()) - { - endpoint += "/v1/logs"; - } - } - return endpoint.size() ? endpoint : kOtlpEndpointDefault; + return GetOtlpDefaultTracesSslCertificateString(); } -inline const std::chrono::system_clock::duration GetOtlpDefaultLogTimeout() -{ - constexpr char kOtlpLogsTimeoutEnv[] = "OTEL_EXPORTER_OTLP_LOGS_TIMEOUT"; - constexpr char kOtlpTimeoutEnv[] = "OTEL_EXPORTER_OTLP_TIMEOUT"; +std::string GetOtlpDefaultTracesSslClientKeyPath(); +std::string GetOtlpDefaultMetricsSslClientKeyPath(); +std::string GetOtlpDefaultLogsSslClientKeyPath(); - auto timeout = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpLogsTimeoutEnv); - if (timeout.empty()) - { - timeout = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTimeoutEnv); - } - return GetOtlpTimeoutFromString(timeout.c_str()); -} +std::string GetOtlpDefaultTracesSslClientKeyString(); +std::string GetOtlpDefaultMetricsSslClientKeyString(); +std::string GetOtlpDefaultLogsSslClientKeyString(); -inline OtlpHeaders GetOtlpDefaultLogHeaders() -{ - constexpr char kOtlpLogsHeadersEnv[] = "OTEL_EXPORTER_OTLP_LOGS_HEADERS"; - constexpr char kOtlpHeadersEnv[] = "OTEL_EXPORTER_OTLP_HEADERS"; +std::string GetOtlpDefaultTracesSslClientCertificatePath(); +std::string GetOtlpDefaultMetricsSslClientCertificatePath(); +std::string GetOtlpDefaultLogsSslClientCertificatePath(); - OtlpHeaders result; - std::unordered_set log_remove_cache; - DumpOtlpHeaders(result, kOtlpHeadersEnv, log_remove_cache); +std::string GetOtlpDefaultTracesSslClientCertificateString(); +std::string GetOtlpDefaultMetricsSslClientCertificateString(); +std::string GetOtlpDefaultLogsSslClientCertificateString(); - log_remove_cache.clear(); - DumpOtlpHeaders(result, kOtlpLogsHeadersEnv, log_remove_cache); +#ifdef ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW +std::string GetOtlpDefaultTracesSslTlsMinVersion(); +std::string GetOtlpDefaultMetricsSslTlsMinVersion(); +std::string GetOtlpDefaultLogsSslTlsMinVersion(); - return result; -} +std::string GetOtlpDefaultTracesSslTlsMaxVersion(); +std::string GetOtlpDefaultMetricsSslTlsMaxVersion(); +std::string GetOtlpDefaultLogsSslTlsMaxVersion(); -// --- Metrics Environment Variables -inline const std::string GetOtlpDefaultMetricsEndpoint() -{ - constexpr char kOtlpMetricsEndpointEnv[] = "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT"; - constexpr char kOtlpEndpointEnv[] = "OTEL_EXPORTER_OTLP_ENDPOINT"; - constexpr char kOtlpEndpointDefault[] = "http://localhost:4318/v1/metrics"; +// For TLS 1.0, 1.1, 1.2 +std::string GetOtlpDefaultTracesSslTlsCipher(); +std::string GetOtlpDefaultMetricsSslTlsCipher(); +std::string GetOtlpDefaultLogsSslTlsCipher(); - auto endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpMetricsEndpointEnv); - if (endpoint.empty()) - { - endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpEndpointEnv); - if (!endpoint.empty()) - { - endpoint += "/v1/metrics"; - } - } - return endpoint.size() ? endpoint : kOtlpEndpointDefault; -} +// For TLS 1.3 +std::string GetOtlpDefaultTracesSslTlsCipherSuite(); +std::string GetOtlpDefaultMetricsSslTlsCipherSuite(); +std::string GetOtlpDefaultLogsSslTlsCipherSuite(); +#endif /* ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW */ -inline const std::chrono::system_clock::duration GetOtlpDefaultMetricsTimeout() -{ - constexpr char kOtlpMetricsTimeoutEnv[] = "OTEL_EXPORTER_OTLP_METRICS_TIMEOUT"; - constexpr char kOtlpTimeoutEnv[] = "OTEL_EXPORTER_OTLP_TIMEOUT"; +std::chrono::system_clock::duration GetOtlpDefaultTracesTimeout(); +std::chrono::system_clock::duration GetOtlpDefaultMetricsTimeout(); +std::chrono::system_clock::duration GetOtlpDefaultLogsTimeout(); - auto timeout = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpMetricsTimeoutEnv); - if (timeout.empty()) - { - timeout = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTimeoutEnv); - } - return GetOtlpTimeoutFromString(timeout.c_str()); -} - -inline OtlpHeaders GetOtlpDefaultMetricsHeaders() +// Compatibility with OTELCPP 1.8.2 +inline std::chrono::system_clock::duration GetOtlpDefaultTimeout() { - constexpr char kOtlpMetricsHeadersEnv[] = "OTEL_EXPORTER_OTLP_METRICS_HEADERS"; - constexpr char kOtlpHeadersEnv[] = "OTEL_EXPORTER_OTLP_HEADERS"; - - OtlpHeaders result; - std::unordered_set metric_remove_cache; - DumpOtlpHeaders(result, kOtlpHeadersEnv, metric_remove_cache); - - metric_remove_cache.clear(); - DumpOtlpHeaders(result, kOtlpMetricsHeadersEnv, metric_remove_cache); - - return result; + return GetOtlpDefaultTracesTimeout(); } -inline bool GetOtlpDefaultMetricsIsSslEnable() +struct cmp_ic { - constexpr char kOtlpMetricsIsSslEnableEnv[] = "OTEL_EXPORTER_OTLP_METRICS_SSL_ENABLE"; - constexpr char kOtlpIsSslEnableEnv[] = "OTEL_EXPORTER_OTLP_SSL_ENABLE"; - - auto ssl_enable = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpMetricsIsSslEnableEnv); - if (ssl_enable.empty()) - { - ssl_enable = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpIsSslEnableEnv); - } - if (ssl_enable == "True" || ssl_enable == "TRUE" || ssl_enable == "true" || ssl_enable == "1") + bool operator()(const std::string &s1, const std::string &s2) const { - return true; + return std::lexicographical_compare( + s1.begin(), s1.end(), s2.begin(), s2.end(), + [](char c1, char c2) { return ::tolower(c1) < ::tolower(c2); }); } - return false; -} +}; +using OtlpHeaders = std::multimap; -inline const std::string GetOtlpDefaultMetricsSslCertificatePath() -{ - constexpr char kOtlpMetricsSslCertificate[] = "OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE"; - constexpr char kOtlpSslCertificate[] = "OTEL_EXPORTER_OTLP_CERTIFICATE"; - auto ssl_cert_path = - opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpMetricsSslCertificate); - if (ssl_cert_path.empty()) - { - ssl_cert_path = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpSslCertificate); - } - return ssl_cert_path.size() ? ssl_cert_path : ""; -} +OtlpHeaders GetOtlpDefaultTracesHeaders(); +OtlpHeaders GetOtlpDefaultMetricsHeaders(); +OtlpHeaders GetOtlpDefaultLogsHeaders(); -inline const std::string GetOtlpDefaultMetricsSslCertificateString() +// Compatibility with OTELCPP 1.8.2 +inline OtlpHeaders GetOtlpDefaultHeaders() { - constexpr char kOtlpTracesSslCertificateString[] = - "OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE_STRING"; - constexpr char kOtlpSslCertificateString[] = "OTEL_EXPORTER_OTLP_CERTIFICATE_STRING"; - auto ssl_cert = - opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpTracesSslCertificateString); - if (ssl_cert.empty()) - { - ssl_cert = opentelemetry::sdk::common::GetEnvironmentVariable(kOtlpSslCertificateString); - } - return ssl_cert.size() ? ssl_cert : ""; + return GetOtlpDefaultTracesHeaders(); } } // namespace otlp diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_exporter.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_exporter.h index a28e6fca85..ab64d7e769 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_exporter.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_exporter.h @@ -52,6 +52,14 @@ class OtlpGrpcExporter final : public opentelemetry::sdk::trace::SpanExporter sdk::common::ExportResult Export( const nostd::span> &spans) noexcept override; + /** + * Force flush the exporter. + * @param timeout an option timeout, default to max. + * @return return true when all data are exported, and false when timeout + */ + bool ForceFlush( + std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override; + /** * Shut down the exporter. * @param timeout an optional timeout, the default timeout of 0 means that no diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_exporter_factory.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_exporter_factory.h index e258917df9..518cf8b82c 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_exporter_factory.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_exporter_factory.h @@ -17,7 +17,7 @@ namespace otlp /** * Factory class for OtlpGrpcExporter. */ -class OtlpGrpcExporterFactory +class OPENTELEMETRY_EXPORT OtlpGrpcExporterFactory { public: /** diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_exporter_options.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_exporter_options.h index 664ee2934b..f5a2b9d295 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_exporter_options.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_exporter_options.h @@ -14,7 +14,7 @@ namespace otlp { /** - * Struct to hold OTLP exporter options. + * Struct to hold OTLP GRPC traces exporter options. */ struct OtlpGrpcExporterOptions { diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_log_record_exporter.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_log_record_exporter.h index 05224550a3..becb308ca2 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_log_record_exporter.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_log_record_exporter.h @@ -55,6 +55,14 @@ class OtlpGrpcLogRecordExporter : public opentelemetry::sdk::logs::LogRecordExpo const nostd::span> &records) noexcept override; + /** + * Force flush the exporter. + * @param timeout an option timeout, default to max. + * @return return true when all data are exported, and false when timeout + */ + bool ForceFlush( + std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override; + /** * Shutdown this exporter. * @param timeout The maximum time to wait for the shutdown method to return. diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_log_record_exporter_factory.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_log_record_exporter_factory.h index 84e5aa1e96..a6fa8e50d6 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_log_record_exporter_factory.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_log_record_exporter_factory.h @@ -17,7 +17,7 @@ namespace otlp /** * Factory class for OtlpGrpcLogRecordExporter. */ -class OtlpGrpcLogRecordExporterFactory +class OPENTELEMETRY_EXPORT OtlpGrpcLogRecordExporterFactory { public: /** diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_metric_exporter_options.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_metric_exporter_options.h index 61828fd49e..b3d5f9b9a7 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_metric_exporter_options.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_metric_exporter_options.h @@ -15,7 +15,7 @@ namespace otlp { /** - * Struct to hold OTLP metrics exporter options. + * Struct to hold OTLP GRPC metrics exporter options. */ struct OtlpGrpcMetricExporterOptions : public OtlpGrpcExporterOptions { diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_client.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_client.h index 4cc3236da8..c41ffb0914 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_client.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_client.h @@ -49,6 +49,11 @@ struct OtlpHttpClientOptions { std::string url; +#ifdef ENABLE_OTLP_HTTP_SSL_PREVIEW + /** SSL options. */ + ext::http::client::HttpSslOptions ssl_options; +#endif /* ENABLE_OTLP_HTTP_SSL_PREVIEW */ + // By default, post json data HttpRequestContentType content_type = HttpRequestContentType::kJson; @@ -63,11 +68,10 @@ struct OtlpHttpClientOptions // Whether to print the status of the HTTP client in the console bool console_debug = false; - // TODO: Enable/disable to verify SSL certificate - std::chrono::system_clock::duration timeout = GetOtlpDefaultTimeout(); + std::chrono::system_clock::duration timeout; // Additional HTTP headers - OtlpHeaders http_headers = GetOtlpDefaultHeaders(); + OtlpHeaders http_headers; // Concurrent requests std::size_t max_concurrent_requests = 64; @@ -76,9 +80,24 @@ struct OtlpHttpClientOptions std::size_t max_requests_per_connection = 8; // User agent - std::string user_agent = GetOtlpDefaultUserAgent(); + std::string user_agent; inline OtlpHttpClientOptions(nostd::string_view input_url, +#ifdef ENABLE_OTLP_HTTP_SSL_PREVIEW + bool input_ssl_insecure_skip_verify, + nostd::string_view input_ssl_ca_cert_path, + nostd::string_view input_ssl_ca_cert_string, + nostd::string_view input_ssl_client_key_path, + nostd::string_view input_ssl_client_key_string, + nostd::string_view input_ssl_client_cert_path, + nostd::string_view input_ssl_client_cert_string, +#endif /* ENABLE_OTLP_HTTP_SSL_PREVIEW */ +#ifdef ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW + nostd::string_view input_ssl_min_tls, + nostd::string_view input_ssl_max_tls, + nostd::string_view input_ssl_cipher, + nostd::string_view input_ssl_cipher_suite, +#endif /* ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW */ HttpRequestContentType input_content_type, JsonBytesMappingKind input_json_bytes_mapping, bool input_use_json_name, @@ -89,6 +108,24 @@ struct OtlpHttpClientOptions std::size_t input_max_requests_per_connection = 8, nostd::string_view input_user_agent = GetOtlpDefaultUserAgent()) : url(input_url), +#ifdef ENABLE_OTLP_HTTP_SSL_PREVIEW + ssl_options(input_url, + input_ssl_insecure_skip_verify, + input_ssl_ca_cert_path, + input_ssl_ca_cert_string, + input_ssl_client_key_path, + input_ssl_client_key_string, + input_ssl_client_cert_path, + input_ssl_client_cert_string +# ifdef ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW + , + input_ssl_min_tls, + input_ssl_max_tls, + input_ssl_cipher, + input_ssl_cipher_suite +# endif /* ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW */ + ), +#endif /* ENABLE_OTLP_HTTP_SSL_PREVIEW */ content_type(input_content_type), json_bytes_mapping(input_json_bytes_mapping), use_json_name(input_use_json_name), diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_exporter.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_exporter.h index 673e0d0bb3..9188858fc1 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_exporter.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_exporter.h @@ -53,6 +53,14 @@ class OtlpHttpExporter final : public opentelemetry::sdk::trace::SpanExporter const nostd::span> &spans) noexcept override; + /** + * Force flush the exporter. + * @param timeout an option timeout, default to max. + * @return return true when all data are exported, and false when timeout + */ + bool ForceFlush( + std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override; + /** * Shut down the exporter. * @param timeout an optional timeout, the default timeout of 0 means that no diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_exporter_factory.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_exporter_factory.h index e3deaca1ba..5316528365 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_exporter_factory.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_exporter_factory.h @@ -17,7 +17,7 @@ namespace otlp /** * Factory class for OtlpHttpExporter. */ -class OtlpHttpExporterFactory +class OPENTELEMETRY_EXPORT OtlpHttpExporterFactory { public: /** diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_exporter_options.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_exporter_options.h index 9f84b2c6a5..29b4b76ec0 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_exporter_options.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_exporter_options.h @@ -19,7 +19,7 @@ namespace otlp { /** - * Struct to hold OTLP exporter options. + * Struct to hold OTLP HTTP traces exporter options. */ struct OtlpHttpExporterOptions { @@ -43,7 +43,6 @@ struct OtlpHttpExporterOptions // Whether to print the status of the exporter in the console bool console_debug = false; - // TODO: Enable/disable to verify SSL certificate std::chrono::system_clock::duration timeout = GetOtlpDefaultTimeout(); // Additional HTTP headers @@ -57,6 +56,30 @@ struct OtlpHttpExporterOptions // Requests per connections std::size_t max_requests_per_connection = 8; #endif + +#ifdef ENABLE_OTLP_HTTP_SSL_PREVIEW + bool ssl_insecure_skip_verify{false}; + + std::string ssl_ca_cert_path = GetOtlpDefaultTracesSslCertificatePath(); + std::string ssl_ca_cert_string = GetOtlpDefaultTracesSslCertificateString(); + + std::string ssl_client_key_path = GetOtlpDefaultTracesSslClientKeyPath(); + std::string ssl_client_key_string = GetOtlpDefaultTracesSslClientKeyString(); + + std::string ssl_client_cert_path = GetOtlpDefaultTracesSslClientCertificatePath(); + std::string ssl_client_cert_string = GetOtlpDefaultTracesSslClientCertificateString(); +#endif /* ENABLE_OTLP_HTTP_SSL_PREVIEW */ + +#ifdef ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW + /** Minimum TLS version. */ + std::string ssl_min_tls = GetOtlpDefaultTracesSslTlsMinVersion(); + /** Maximum TLS version. */ + std::string ssl_max_tls = GetOtlpDefaultTracesSslTlsMaxVersion(); + /** TLS cipher. */ + std::string ssl_cipher = GetOtlpDefaultTracesSslTlsCipher(); + /** TLS cipher suite. */ + std::string ssl_cipher_suite = GetOtlpDefaultTracesSslTlsCipherSuite(); +#endif /* ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW */ }; } // namespace otlp diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_log_record_exporter.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_log_record_exporter.h index 2250cfe831..035b046b72 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_log_record_exporter.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_log_record_exporter.h @@ -53,6 +53,14 @@ class OtlpHttpLogRecordExporter final : public opentelemetry::sdk::logs::LogReco const nostd::span> &records) noexcept override; + /** + * Force flush the exporter. + * @param timeout an option timeout, default to max. + * @return return true when all data are exported, and false when timeout + */ + bool ForceFlush( + std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override; + /** * Shutdown this exporter. * @param timeout The maximum time to wait for the shutdown method to return diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_log_record_exporter_factory.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_log_record_exporter_factory.h index d2ea095245..152a394574 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_log_record_exporter_factory.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_log_record_exporter_factory.h @@ -18,7 +18,7 @@ namespace otlp /** * Factory class for OtlpHttpLogRecordExporter. */ -class OtlpHttpLogRecordExporterFactory +class OPENTELEMETRY_EXPORT OtlpHttpLogRecordExporterFactory { public: /** diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_log_record_exporter_options.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_log_record_exporter_options.h index 4ad5d82005..e785170329 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_log_record_exporter_options.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_log_record_exporter_options.h @@ -20,7 +20,7 @@ namespace otlp { /** - * Struct to hold OTLP exporter options. + * Struct to hold OTLP HTTP logs exporter options. */ struct OtlpHttpLogRecordExporterOptions { @@ -28,7 +28,7 @@ struct OtlpHttpLogRecordExporterOptions // @see // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/otlp.md // @see https://github.com/open-telemetry/opentelemetry-collector/tree/main/receiver/otlpreceiver - std::string url = GetOtlpDefaultHttpLogEndpoint(); + std::string url = GetOtlpDefaultHttpLogsEndpoint(); // By default, post json data HttpRequestContentType content_type = HttpRequestContentType::kJson; @@ -44,11 +44,10 @@ struct OtlpHttpLogRecordExporterOptions // Whether to print the status of the exporter in the console bool console_debug = false; - // TODO: Enable/disable to verify SSL certificate - std::chrono::system_clock::duration timeout = GetOtlpDefaultLogTimeout(); + std::chrono::system_clock::duration timeout = GetOtlpDefaultLogsTimeout(); // Additional HTTP headers - OtlpHeaders http_headers = GetOtlpDefaultLogHeaders(); + OtlpHeaders http_headers = GetOtlpDefaultLogsHeaders(); # ifdef ENABLE_ASYNC_EXPORT // Concurrent requests @@ -58,6 +57,30 @@ struct OtlpHttpLogRecordExporterOptions // Requests per connections std::size_t max_requests_per_connection = 8; # endif + +# ifdef ENABLE_OTLP_HTTP_SSL_PREVIEW + bool ssl_insecure_skip_verify{false}; + + std::string ssl_ca_cert_path = GetOtlpDefaultLogsSslCertificatePath(); + std::string ssl_ca_cert_string = GetOtlpDefaultLogsSslCertificateString(); + + std::string ssl_client_key_path = GetOtlpDefaultLogsSslClientKeyPath(); + std::string ssl_client_key_string = GetOtlpDefaultLogsSslClientKeyString(); + + std::string ssl_client_cert_path = GetOtlpDefaultLogsSslClientCertificatePath(); + std::string ssl_client_cert_string = GetOtlpDefaultLogsSslClientCertificateString(); +# endif /* ENABLE_OTLP_HTTP_SSL_PREVIEW */ + +# ifdef ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW + /** Minimum TLS version. */ + std::string ssl_min_tls = GetOtlpDefaultLogsSslTlsMinVersion(); + /** Maximum TLS version. */ + std::string ssl_max_tls = GetOtlpDefaultLogsSslTlsMaxVersion(); + /** TLS cipher. */ + std::string ssl_cipher = GetOtlpDefaultLogsSslTlsCipher(); + /** TLS cipher suite. */ + std::string ssl_cipher_suite = GetOtlpDefaultLogsSslTlsCipherSuite(); +# endif /* ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW */ }; } // namespace otlp diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_metric_exporter_options.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_metric_exporter_options.h index 140b5b886b..e37e123097 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_metric_exporter_options.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_http_metric_exporter_options.h @@ -19,7 +19,7 @@ namespace otlp { /** - * Struct to hold OTLP exporter options. + * Struct to hold OTLP HTTP metrics exporter options. */ struct OtlpHttpMetricExporterOptions { @@ -61,6 +61,30 @@ struct OtlpHttpMetricExporterOptions // Requests per connections std::size_t max_requests_per_connection = 8; #endif + +#ifdef ENABLE_OTLP_HTTP_SSL_PREVIEW + bool ssl_insecure_skip_verify{false}; + + std::string ssl_ca_cert_path = GetOtlpDefaultMetricsSslCertificatePath(); + std::string ssl_ca_cert_string = GetOtlpDefaultMetricsSslCertificateString(); + + std::string ssl_client_key_path = GetOtlpDefaultMetricsSslClientKeyPath(); + std::string ssl_client_key_string = GetOtlpDefaultMetricsSslClientKeyString(); + + std::string ssl_client_cert_path = GetOtlpDefaultMetricsSslClientCertificatePath(); + std::string ssl_client_cert_string = GetOtlpDefaultMetricsSslClientCertificateString(); +#endif /* ENABLE_OTLP_HTTP_SSL_PREVIEW */ + +#ifdef ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW + /** Minimum TLS version. */ + std::string ssl_min_tls = GetOtlpDefaultMetricsSslTlsMinVersion(); + /** Maximum TLS version. */ + std::string ssl_max_tls = GetOtlpDefaultMetricsSslTlsMaxVersion(); + /** TLS cipher. */ + std::string ssl_cipher = GetOtlpDefaultMetricsSslTlsCipher(); + /** TLS cipher suite. */ + std::string ssl_cipher_suite = GetOtlpDefaultMetricsSslTlsCipherSuite(); +#endif /* ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW */ }; } // namespace otlp diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/protobuf_include_prefix.h b/exporters/otlp/include/opentelemetry/exporters/otlp/protobuf_include_prefix.h index 036cb0ae7f..dc674ce9eb 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/protobuf_include_prefix.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/protobuf_include_prefix.h @@ -22,6 +22,9 @@ # pragma warning(disable : 4267) # pragma warning(disable : 4668) # pragma warning(disable : 4946) +# pragma warning(disable : 6001) +# pragma warning(disable : 6244) +# pragma warning(disable : 6246) #endif #if defined(__GNUC__) && !defined(__clang__) && !defined(__apple_build_version__) @@ -30,9 +33,34 @@ # endif # pragma GCC diagnostic ignored "-Wunused-parameter" # pragma GCC diagnostic ignored "-Wtype-limits" +# pragma GCC diagnostic ignored "-Wsign-compare" +# pragma GCC diagnostic ignored "-Wsign-conversion" +# pragma GCC diagnostic ignored "-Wshadow" +# pragma GCC diagnostic ignored "-Wuninitialized" +# pragma GCC diagnostic ignored "-Wconversion" +# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 409 +# pragma GCC diagnostic ignored "-Wfloat-conversion" +# endif +# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 501 +# pragma GCC diagnostic ignored "-Wsuggest-override" +# endif #elif defined(__clang__) || defined(__apple_build_version__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunused-parameter" # pragma clang diagnostic ignored "-Wtype-limits" # pragma clang diagnostic ignored "-Wshadow-field" +# pragma clang diagnostic ignored "-Wsign-compare" +# pragma clang diagnostic ignored "-Wsign-conversion" +# pragma clang diagnostic ignored "-Wshadow" +# pragma clang diagnostic ignored "-Wuninitialized" +# pragma clang diagnostic ignored "-Wconversion" +# if ((__clang_major__ * 100) + __clang_minor__) >= 305 +# pragma clang diagnostic ignored "-Wfloat-conversion" +# endif +# if ((__clang_major__ * 100) + __clang_minor__) >= 306 +# pragma clang diagnostic ignored "-Winconsistent-missing-override" +# endif +# if ((__clang_major__ * 100) + __clang_minor__) >= 1100 +# pragma clang diagnostic ignored "-Wsuggest-override" +# endif #endif diff --git a/exporters/otlp/src/otlp_environment.cc b/exporters/otlp/src/otlp_environment.cc new file mode 100644 index 0000000000..5324b40213 --- /dev/null +++ b/exporters/otlp/src/otlp_environment.cc @@ -0,0 +1,1006 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/exporters/otlp/otlp_environment.h" + +#include "opentelemetry/sdk/common/env_variables.h" +#include "opentelemetry/sdk/version/version.h" + +#include "opentelemetry/sdk/common/global_log_handler.h" +#include "opentelemetry/sdk_config.h" + +namespace nostd = opentelemetry::nostd; +namespace sdk_common = opentelemetry::sdk::common; + +/* + TODO: + - Document new variables + - Announce deprecation in CHANGELOG + - Activate deprecation warning +*/ +/* #define WARN_DEPRECATED_ENV */ + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace exporter +{ +namespace otlp +{ + +static bool GetBoolDualEnvVar(const char *signal_name, const char *generic_name, bool &value) +{ + bool exists; + + exists = sdk_common::GetBoolEnvironmentVariable(signal_name, value); + if (exists) + { + return true; + } + + exists = sdk_common::GetBoolEnvironmentVariable(generic_name, value); + + return exists; +} + +static bool GetDurationDualEnvVar(const char *signal_name, + const char *generic_name, + std::chrono::system_clock::duration &value) +{ + bool exists; + + exists = sdk_common::GetDurationEnvironmentVariable(signal_name, value); + if (exists) + { + return true; + } + + exists = sdk_common::GetDurationEnvironmentVariable(generic_name, value); + + return exists; +} + +static bool GetStringDualEnvVar(const char *signal_name, + const char *generic_name, + std::string &value) +{ + bool exists; + + exists = sdk_common::GetStringEnvironmentVariable(signal_name, value); + if (exists) + { + return true; + } + + exists = sdk_common::GetStringEnvironmentVariable(generic_name, value); + + return exists; +} + +std::string GetOtlpDefaultGrpcTracesEndpoint() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_ENDPOINT"; + constexpr char kDefault[] = "http://localhost:4317"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + + if (exists) + { + return value; + } + + return kDefault; +} + +std::string GetOtlpDefaultGrpcMetricsEndpoint() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_ENDPOINT"; + constexpr char kDefault[] = "http://localhost:4317"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + + if (exists) + { + return value; + } + + return kDefault; +} + +std::string GetOtlpDefaultGrpcLogsEndpoint() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_ENDPOINT"; + constexpr char kDefault[] = "http://localhost:4317"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + + if (exists) + { + return value; + } + + return kDefault; +} + +std::string GetOtlpDefaultHttpTracesEndpoint() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_ENDPOINT"; + constexpr char kDefault[] = "http://localhost:4318/v1/traces"; + + std::string value; + bool exists; + + exists = sdk_common::GetStringEnvironmentVariable(kSignalEnv, value); + if (exists) + { + return value; + } + + exists = sdk_common::GetStringEnvironmentVariable(kGenericEnv, value); + if (exists) + { + value += "/v1/traces"; + return value; + } + + return kDefault; +} + +std::string GetOtlpDefaultHttpMetricsEndpoint() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_ENDPOINT"; + constexpr char kDefault[] = "http://localhost:4318/v1/metrics"; + + std::string value; + bool exists; + + exists = sdk_common::GetStringEnvironmentVariable(kSignalEnv, value); + if (exists) + { + return value; + } + + exists = sdk_common::GetStringEnvironmentVariable(kGenericEnv, value); + if (exists) + { + value += "/v1/metrics"; + return value; + } + + return kDefault; +} + +std::string GetOtlpDefaultHttpLogsEndpoint() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_ENDPOINT"; + constexpr char kDefault[] = "http://localhost:4318/v1/logs"; + + std::string value; + bool exists; + + exists = sdk_common::GetStringEnvironmentVariable(kSignalEnv, value); + if (exists) + { + return value; + } + + exists = sdk_common::GetStringEnvironmentVariable(kGenericEnv, value); + if (exists) + { + value += "/v1/logs"; + return value; + } + + return kDefault; +} + +bool GetOtlpDefaultGrpcTracesIsInsecure() +{ + std::string endpoint = GetOtlpDefaultGrpcTracesEndpoint(); + + /* The trace endpoint, when providing a scheme, takes precedence. */ + + if (endpoint.substr(0, 6) == "https:") + { + return false; + } + + if (endpoint.substr(0, 5) == "http:") + { + return true; + } + + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_TRACES_INSECURE"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_INSECURE"; + constexpr char kOldSignalEnv[] = "OTEL_EXPORTER_OTLP_TRACES_SSL_ENABLE"; + constexpr char kOldGenericEnv[] = "OTEL_EXPORTER_OTLP_SSL_ENABLE"; + + bool insecure; + bool ssl_enabled; + bool exists; + + exists = GetBoolDualEnvVar(kSignalEnv, kGenericEnv, insecure); + if (exists) + { + return insecure; + } + + exists = sdk_common::GetBoolEnvironmentVariable(kOldSignalEnv, ssl_enabled); + if (exists) + { +#ifdef WARN_DEPRECATED_ENV + OTEL_INTERNAL_LOG_WARN("Environment variable <" << kOldSignalEnv << "> is deprecated, use <" + << kSignalEnv << "> instead."); +#endif + + insecure = !ssl_enabled; + return insecure; + } + + exists = sdk_common::GetBoolEnvironmentVariable(kOldGenericEnv, ssl_enabled); + if (exists) + { +#ifdef WARN_DEPRECATED_ENV + OTEL_INTERNAL_LOG_WARN("Environment variable <" << kOldGenericEnv << "> is deprecated, use <" + << kGenericEnv << "> instead."); +#endif + + insecure = !ssl_enabled; + return insecure; + } + + return false; +} + +bool GetOtlpDefaultGrpcMetricsIsInsecure() +{ + std::string endpoint = GetOtlpDefaultGrpcMetricsEndpoint(); + + /* The metrics endpoint, when providing a scheme, takes precedence. */ + + if (endpoint.substr(0, 6) == "https:") + { + return false; + } + + if (endpoint.substr(0, 5) == "http:") + { + return true; + } + + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_METRICS_INSECURE"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_INSECURE"; + constexpr char kOldSignalEnv[] = "OTEL_EXPORTER_OTLP_METRICS_SSL_ENABLE"; + constexpr char kOldGenericEnv[] = "OTEL_EXPORTER_OTLP_SSL_ENABLE"; + + bool insecure; + bool ssl_enabled; + bool exists; + + exists = GetBoolDualEnvVar(kSignalEnv, kGenericEnv, insecure); + if (exists) + { + return insecure; + } + + exists = sdk_common::GetBoolEnvironmentVariable(kOldSignalEnv, ssl_enabled); + if (exists) + { +#ifdef WARN_DEPRECATED_ENV + OTEL_INTERNAL_LOG_WARN("Environment variable <" << kOldSignalEnv << "> is deprecated, use <" + << kSignalEnv << "> instead."); +#endif + + insecure = !ssl_enabled; + return insecure; + } + + exists = sdk_common::GetBoolEnvironmentVariable(kOldGenericEnv, ssl_enabled); + if (exists) + { +#ifdef WARN_DEPRECATED_ENV + OTEL_INTERNAL_LOG_WARN("Environment variable <" << kOldGenericEnv << "> is deprecated, use <" + << kGenericEnv << "> instead."); +#endif + + insecure = !ssl_enabled; + return insecure; + } + + return false; +} + +bool GetOtlpDefaultGrpcLogsIsInsecure() +{ + std::string endpoint = GetOtlpDefaultGrpcLogsEndpoint(); + + /* The logs endpoint, when providing a scheme, takes precedence. */ + + if (endpoint.substr(0, 6) == "https:") + { + return false; + } + + if (endpoint.substr(0, 5) == "http:") + { + return true; + } + + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_LOGS_INSECURE"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_INSECURE"; + + bool insecure; + bool exists; + + exists = GetBoolDualEnvVar(kSignalEnv, kGenericEnv, insecure); + if (exists) + { + return insecure; + } + + return false; +} + +std::string GetOtlpDefaultTracesSslCertificatePath() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CERTIFICATE"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultMetricsSslCertificatePath() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CERTIFICATE"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultLogsSslCertificatePath() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CERTIFICATE"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultTracesSslCertificateString() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE_STRING"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CERTIFICATE_STRING"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultMetricsSslCertificateString() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE_STRING"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CERTIFICATE_STRING"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultLogsSslCertificateString() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE_STRING"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CERTIFICATE_STRING"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultTracesSslClientKeyPath() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CLIENT_KEY"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultMetricsSslClientKeyPath() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_METRICS_CLIENT_KEY"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CLIENT_KEY"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultLogsSslClientKeyPath() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_LOGS_CLIENT_KEY"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CLIENT_KEY"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultTracesSslClientKeyString() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY_STRING"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CLIENT_KEY_STRING"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultMetricsSslClientKeyString() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_METRICS_CLIENT_KEY_STRING"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CLIENT_KEY_STRING"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultLogsSslClientKeyString() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_LOGS_CLIENT_KEY_STRING"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CLIENT_KEY_STRING"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultTracesSslClientCertificatePath() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_TRACES_CLIENT_CERTIFICATE"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultMetricsSslClientCertificatePath() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_METRICS_CLIENT_CERTIFICATE"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultLogsSslClientCertificatePath() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_LOGS_CLIENT_CERTIFICATE"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultTracesSslClientCertificateString() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_TRACES_CLIENT_CERTIFICATE_STRING"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE_STRING"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultMetricsSslClientCertificateString() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_METRICS_CLIENT_CERTIFICATE_STRING"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE_STRING"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultLogsSslClientCertificateString() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_LOGS_CLIENT_CERTIFICATE_STRING"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE_STRING"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +#ifdef ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW + +/* + EXPERIMENTAL: + Environment variable names do not exist in the spec, + using the OTEL_CPP_ namespace. +*/ + +std::string GetOtlpDefaultTracesSslTlsMinVersion() +{ + constexpr char kSignalEnv[] = "OTEL_CPP_EXPORTER_OTLP_TRACES_MIN_TLS"; + constexpr char kGenericEnv[] = "OTEL_CPP_EXPORTER_OTLP_MIN_TLS"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultMetricsSslTlsMinVersion() +{ + constexpr char kSignalEnv[] = "OTEL_CPP_EXPORTER_OTLP_METRICS_MIN_TLS"; + constexpr char kGenericEnv[] = "OTEL_CPP_EXPORTER_OTLP_MIN_TLS"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultLogsSslTlsMinVersion() +{ + constexpr char kSignalEnv[] = "OTEL_CPP_EXPORTER_OTLP_LOGS_MIN_TLS"; + constexpr char kGenericEnv[] = "OTEL_CPP_EXPORTER_OTLP_MIN_TLS"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultTracesSslTlsMaxVersion() +{ + constexpr char kSignalEnv[] = "OTEL_CPP_EXPORTER_OTLP_TRACES_MAX_TLS"; + constexpr char kGenericEnv[] = "OTEL_CPP_EXPORTER_OTLP_MAX_TLS"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultMetricsSslTlsMaxVersion() +{ + constexpr char kSignalEnv[] = "OTEL_CPP_EXPORTER_OTLP_METRICS_MAX_TLS"; + constexpr char kGenericEnv[] = "OTEL_CPP_EXPORTER_OTLP_MAX_TLS"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultLogsSslTlsMaxVersion() +{ + constexpr char kSignalEnv[] = "OTEL_CPP_EXPORTER_OTLP_LOGS_MAX_TLS"; + constexpr char kGenericEnv[] = "OTEL_CPP_EXPORTER_OTLP_MAX_TLS"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultTracesSslTlsCipher() +{ + constexpr char kSignalEnv[] = "OTEL_CPP_EXPORTER_OTLP_TRACES_CIPHER"; + constexpr char kGenericEnv[] = "OTEL_CPP_EXPORTER_OTLP_CIPHER"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultMetricsSslTlsCipher() +{ + constexpr char kSignalEnv[] = "OTEL_CPP_EXPORTER_OTLP_METRICS_CIPHER"; + constexpr char kGenericEnv[] = "OTEL_CPP_EXPORTER_OTLP_CIPHER"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultLogsSslTlsCipher() +{ + constexpr char kSignalEnv[] = "OTEL_CPP_EXPORTER_OTLP_LOGS_CIPHER"; + constexpr char kGenericEnv[] = "OTEL_CPP_EXPORTER_OTLP_CIPHER"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultTracesSslTlsCipherSuite() +{ + constexpr char kSignalEnv[] = "OTEL_CPP_EXPORTER_OTLP_TRACES_CIPHER_SUITE"; + constexpr char kGenericEnv[] = "OTEL_CPP_EXPORTER_OTLP_CIPHER_SUITE"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultMetricsSslTlsCipherSuite() +{ + constexpr char kSignalEnv[] = "OTEL_CPP_EXPORTER_OTLP_METRICS_CIPHER_SUITE"; + constexpr char kGenericEnv[] = "OTEL_CPP_EXPORTER_OTLP_CIPHER_SUITE"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +std::string GetOtlpDefaultLogsSslTlsCipherSuite() +{ + constexpr char kSignalEnv[] = "OTEL_CPP_EXPORTER_OTLP_LOGS_CIPHER_SUITE"; + constexpr char kGenericEnv[] = "OTEL_CPP_EXPORTER_OTLP_CIPHER_SUITE"; + + std::string value; + bool exists; + + exists = GetStringDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + return std::string{}; +} + +#endif /* ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW */ + +std::chrono::system_clock::duration GetOtlpDefaultTracesTimeout() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_TRACES_TIMEOUT"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_TIMEOUT"; + + std::chrono::system_clock::duration value; + bool exists; + + exists = GetDurationDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + value = std::chrono::duration_cast(std::chrono::seconds{10}); + return value; +} + +std::chrono::system_clock::duration GetOtlpDefaultMetricsTimeout() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_METRICS_TIMEOUT"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_TIMEOUT"; + + std::chrono::system_clock::duration value; + bool exists; + + exists = GetDurationDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + value = std::chrono::duration_cast(std::chrono::seconds{10}); + return value; +} + +std::chrono::system_clock::duration GetOtlpDefaultLogsTimeout() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_LOGS_TIMEOUT"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_TIMEOUT"; + + std::chrono::system_clock::duration value; + bool exists; + + exists = GetDurationDualEnvVar(kSignalEnv, kGenericEnv, value); + if (exists) + { + return value; + } + + value = std::chrono::duration_cast(std::chrono::seconds{10}); + return value; +} + +static void DumpOtlpHeaders(OtlpHeaders &output, const char *env_var_name) +{ + std::string raw_value; + bool exists; + + exists = sdk_common::GetStringEnvironmentVariable(env_var_name, raw_value); + + if (!exists) + { + return; + } + + opentelemetry::common::KeyValueStringTokenizer tokenizer{raw_value}; + opentelemetry::nostd::string_view header_key; + opentelemetry::nostd::string_view header_value; + bool header_valid = true; + + std::unordered_set remove_cache; + + while (tokenizer.next(header_valid, header_key, header_value)) + { + if (header_valid) + { + std::string key(header_key); + if (remove_cache.end() == remove_cache.find(key)) + { + remove_cache.insert(key); + auto range = output.equal_range(key); + if (range.first != range.second) + { + output.erase(range.first, range.second); + } + } + + std::string value(header_value); + output.emplace(std::make_pair(std::move(key), std::move(value))); + } + } +} + +static OtlpHeaders GetHeaders(const char *signal_name, const char *generic_name) +{ + OtlpHeaders result; + DumpOtlpHeaders(result, generic_name); + DumpOtlpHeaders(result, signal_name); + + return result; +} + +OtlpHeaders GetOtlpDefaultTracesHeaders() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_TRACES_HEADERS"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_HEADERS"; + + return GetHeaders(kSignalEnv, kGenericEnv); +} + +OtlpHeaders GetOtlpDefaultMetricsHeaders() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_METRICS_HEADERS"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_HEADERS"; + + return GetHeaders(kSignalEnv, kGenericEnv); +} + +OtlpHeaders GetOtlpDefaultLogsHeaders() +{ + constexpr char kSignalEnv[] = "OTEL_EXPORTER_OTLP_LOGS_HEADERS"; + constexpr char kGenericEnv[] = "OTEL_EXPORTER_OTLP_HEADERS"; + + return GetHeaders(kSignalEnv, kGenericEnv); +} + +} // namespace otlp +} // namespace exporter +OPENTELEMETRY_END_NAMESPACE diff --git a/exporters/otlp/src/otlp_grpc_exporter.cc b/exporters/otlp/src/otlp_grpc_exporter.cc index 5f4cbc99e2..89ad1fb2cf 100644 --- a/exporters/otlp/src/otlp_grpc_exporter.cc +++ b/exporters/otlp/src/otlp_grpc_exporter.cc @@ -72,6 +72,13 @@ sdk::common::ExportResult OtlpGrpcExporter::Export( return sdk::common::ExportResult::kSuccess; } +bool OtlpGrpcExporter::ForceFlush(std::chrono::microseconds /* timeout */) noexcept +{ + // TODO: When we implement async exporting in OTLP gRPC exporter in the future, we need wait the + // running exporting finished here. + return true; +} + bool OtlpGrpcExporter::Shutdown(std::chrono::microseconds /* timeout */) noexcept { const std::lock_guard locked(lock_); diff --git a/exporters/otlp/src/otlp_grpc_log_record_exporter.cc b/exporters/otlp/src/otlp_grpc_log_record_exporter.cc index e8a3b8a46a..1873ac8ad7 100644 --- a/exporters/otlp/src/otlp_grpc_log_record_exporter.cc +++ b/exporters/otlp/src/otlp_grpc_log_record_exporter.cc @@ -91,6 +91,13 @@ bool OtlpGrpcLogRecordExporter::Shutdown(std::chrono::microseconds /* timeout */ return true; } +bool OtlpGrpcLogRecordExporter::ForceFlush(std::chrono::microseconds /* timeout */) noexcept +{ + // TODO: When we implement async exporting in OTLP gRPC exporter in the future, we need wait the + // running exporting finished here. + return true; +} + bool OtlpGrpcLogRecordExporter::isShutdown() const noexcept { const std::lock_guard locked(lock_); diff --git a/exporters/otlp/src/otlp_http_client.cc b/exporters/otlp/src/otlp_http_client.cc index 58cff24c1e..5cbc65952c 100644 --- a/exporters/otlp/src/otlp_http_client.cc +++ b/exporters/otlp/src/otlp_http_client.cc @@ -793,34 +793,40 @@ bool OtlpHttpClient::ForceFlush(std::chrono::microseconds timeout) noexcept // Wait for all the sessions to finish std::unique_lock lock(session_waker_lock_); - if (timeout <= std::chrono::microseconds::zero()) + + std::chrono::steady_clock::duration timeout_steady = + std::chrono::duration_cast(timeout); + if (timeout_steady <= std::chrono::steady_clock::duration::zero()) + { + timeout_steady = std::chrono::steady_clock::duration::max(); + } + + while (timeout_steady > std::chrono::steady_clock::duration::zero()) { - while (true) { + std::lock_guard guard{session_manager_lock_}; + if (running_sessions_.empty()) { - std::lock_guard guard{session_manager_lock_}; - if (running_sessions_.empty()) - { - break; - } - } - // When changes of running_sessions_ and notify_one/notify_all happen between predicate - // checking and waiting, we should not wait forever.We should cleanup gc sessions here as soon - // as possible to call FinishSession() and cleanup resources. - if (std::cv_status::timeout == session_waker_.wait_for(lock, options_.timeout)) - { - cleanupGCSessions(); + break; } } - return true; - } - else - { - return session_waker_.wait_for(lock, timeout, [this] { - std::lock_guard guard{session_manager_lock_}; - return running_sessions_.empty(); - }); + // When changes of running_sessions_ and notify_one/notify_all happen between predicate + // checking and waiting, we should not wait forever.We should cleanup gc sessions here as soon + // as possible to call FinishSession() and cleanup resources. + std::chrono::steady_clock::time_point start_timepoint = std::chrono::steady_clock::now(); + if (std::cv_status::timeout == session_waker_.wait_for(lock, options_.timeout)) + { + cleanupGCSessions(); + } + else + { + break; + } + + timeout_steady -= std::chrono::steady_clock::now() - start_timepoint; } + + return timeout_steady > std::chrono::steady_clock::duration::zero(); } bool OtlpHttpClient::Shutdown(std::chrono::microseconds timeout) noexcept @@ -961,6 +967,9 @@ OtlpHttpClient::createSession( request->AddHeader(header.first, header.second); } request->SetUri(http_uri_); +#ifdef ENABLE_OTLP_HTTP_SSL_PREVIEW + request->SetSslOptions(options_.ssl_options); +#endif /* ENABLE_OTLP_HTTP_SSL_PREVIEW */ request->SetTimeoutMs(std::chrono::duration_cast(options_.timeout)); request->SetMethod(http_client::Method::Post); request->SetBody(body_vec); diff --git a/exporters/otlp/src/otlp_http_exporter.cc b/exporters/otlp/src/otlp_http_exporter.cc index 78b587e766..6732e31431 100644 --- a/exporters/otlp/src/otlp_http_exporter.cc +++ b/exporters/otlp/src/otlp_http_exporter.cc @@ -26,6 +26,21 @@ OtlpHttpExporter::OtlpHttpExporter() : OtlpHttpExporter(OtlpHttpExporterOptions( OtlpHttpExporter::OtlpHttpExporter(const OtlpHttpExporterOptions &options) : options_(options), http_client_(new OtlpHttpClient(OtlpHttpClientOptions(options.url, +#ifdef ENABLE_OTLP_HTTP_SSL_PREVIEW + options.ssl_insecure_skip_verify, + options.ssl_ca_cert_path, + options.ssl_ca_cert_string, + options.ssl_client_key_path, + options.ssl_client_key_string, + options.ssl_client_cert_path, + options.ssl_client_cert_string, +#endif /* ENABLE_OTLP_HTTP_SSL_PREVIEW */ +#ifdef ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW + options.ssl_min_tls, + options.ssl_max_tls, + options.ssl_cipher, + options.ssl_cipher_suite, +#endif /* ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW */ options.content_type, options.json_bytes_mapping, options.use_json_name, @@ -115,6 +130,11 @@ opentelemetry::sdk::common::ExportResult OtlpHttpExporter::Export( #endif } +bool OtlpHttpExporter::ForceFlush(std::chrono::microseconds timeout) noexcept +{ + return http_client_->ForceFlush(timeout); +} + bool OtlpHttpExporter::Shutdown(std::chrono::microseconds timeout) noexcept { return http_client_->Shutdown(timeout); diff --git a/exporters/otlp/src/otlp_http_log_record_exporter.cc b/exporters/otlp/src/otlp_http_log_record_exporter.cc index 81bc37a340..f0d410f6f2 100644 --- a/exporters/otlp/src/otlp_http_log_record_exporter.cc +++ b/exporters/otlp/src/otlp_http_log_record_exporter.cc @@ -31,6 +31,21 @@ OtlpHttpLogRecordExporter::OtlpHttpLogRecordExporter( const OtlpHttpLogRecordExporterOptions &options) : options_(options), http_client_(new OtlpHttpClient(OtlpHttpClientOptions(options.url, +# ifdef ENABLE_OTLP_HTTP_SSL_PREVIEW + options.ssl_insecure_skip_verify, + options.ssl_ca_cert_path, + options.ssl_ca_cert_string, + options.ssl_client_key_path, + options.ssl_client_key_string, + options.ssl_client_cert_path, + options.ssl_client_cert_string, +# endif /* ENABLE_OTLP_HTTP_SSL_PREVIEW */ +# ifdef ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW + options.ssl_min_tls, + options.ssl_max_tls, + options.ssl_cipher, + options.ssl_cipher_suite, +# endif /* ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW */ options.content_type, options.json_bytes_mapping, options.use_json_name, @@ -118,6 +133,11 @@ opentelemetry::sdk::common::ExportResult OtlpHttpLogRecordExporter::Export( # endif } +bool OtlpHttpLogRecordExporter::ForceFlush(std::chrono::microseconds timeout) noexcept +{ + return http_client_->ForceFlush(timeout); +} + bool OtlpHttpLogRecordExporter::Shutdown(std::chrono::microseconds timeout) noexcept { return http_client_->Shutdown(timeout); diff --git a/exporters/otlp/src/otlp_http_metric_exporter.cc b/exporters/otlp/src/otlp_http_metric_exporter.cc index a13c1763fe..e4f667eb3e 100644 --- a/exporters/otlp/src/otlp_http_metric_exporter.cc +++ b/exporters/otlp/src/otlp_http_metric_exporter.cc @@ -29,6 +29,21 @@ OtlpHttpMetricExporter::OtlpHttpMetricExporter(const OtlpHttpMetricExporterOptio aggregation_temporality_selector_{ OtlpMetricUtils::ChooseTemporalitySelector(options_.aggregation_temporality)}, http_client_(new OtlpHttpClient(OtlpHttpClientOptions(options.url, +#ifdef ENABLE_OTLP_HTTP_SSL_PREVIEW + options.ssl_insecure_skip_verify, + options.ssl_ca_cert_path, + options.ssl_ca_cert_string, + options.ssl_client_key_path, + options.ssl_client_key_string, + options.ssl_client_cert_path, + options.ssl_client_cert_string, +#endif /* ENABLE_OTLP_HTTP_SSL_PREVIEW */ +#ifdef ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW + options.ssl_min_tls, + options.ssl_max_tls, + options.ssl_cipher, + options.ssl_cipher_suite, +#endif /* ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW */ options.content_type, options.json_bytes_mapping, options.use_json_name, diff --git a/exporters/otlp/src/otlp_metric_utils.cc b/exporters/otlp/src/otlp_metric_utils.cc index 5224517ece..c51057d772 100644 --- a/exporters/otlp/src/otlp_metric_utils.cc +++ b/exporters/otlp/src/otlp_metric_utils.cc @@ -96,7 +96,9 @@ void OtlpMetricUtils::ConvertHistogramMetric( // sum if ((nostd::holds_alternative(histogram_data.sum_))) { - proto_histogram_point_data->set_sum(nostd::get(histogram_data.sum_)); + // Use static_cast to avoid C4244 in MSVC + proto_histogram_point_data->set_sum( + static_cast(nostd::get(histogram_data.sum_))); } else { @@ -108,7 +110,9 @@ void OtlpMetricUtils::ConvertHistogramMetric( { if (nostd::holds_alternative(histogram_data.min_)) { - proto_histogram_point_data->set_min(nostd::get(histogram_data.min_)); + // Use static_cast to avoid C4244 in MSVC + proto_histogram_point_data->set_min( + static_cast(nostd::get(histogram_data.min_))); } else { @@ -116,7 +120,9 @@ void OtlpMetricUtils::ConvertHistogramMetric( } if (nostd::holds_alternative(histogram_data.max_)) { - proto_histogram_point_data->set_max(nostd::get(histogram_data.max_)); + // Use static_cast to avoid C4244 in MSVC + proto_histogram_point_data->set_max( + static_cast(nostd::get(histogram_data.max_))); } else { @@ -270,7 +276,7 @@ sdk::metrics::AggregationTemporality OtlpMetricUtils::DeltaTemporalitySelector( } sdk::metrics::AggregationTemporality OtlpMetricUtils::CumulativeTemporalitySelector( - sdk::metrics::InstrumentType instrument_type) noexcept + sdk::metrics::InstrumentType /* instrument_type */) noexcept { return sdk::metrics::AggregationTemporality::kCumulative; } diff --git a/exporters/otlp/src/otlp_recordable_utils.cc b/exporters/otlp/src/otlp_recordable_utils.cc index a7f688d7f3..81859ba070 100644 --- a/exporters/otlp/src/otlp_recordable_utils.cc +++ b/exporters/otlp/src/otlp_recordable_utils.cc @@ -117,8 +117,18 @@ void OtlpRecordableUtils::PopulateRequest( if (!output_scope_log->has_scope()) { - output_scope_log->mutable_scope()->set_name(input_scope_log.first->GetName()); - output_scope_log->mutable_scope()->set_version(input_scope_log.first->GetVersion()); + auto proto_scope = output_scope_log->mutable_scope(); + if (proto_scope != nullptr) + { + proto_scope->set_name(input_scope_log.first->GetName()); + proto_scope->set_version(input_scope_log.first->GetVersion()); + + for (auto &scope_attribute : input_scope_log.first->GetAttributes()) + { + OtlpPopulateAttributeUtils::PopulateAttribute( + proto_scope->add_attributes(), scope_attribute.first, scope_attribute.second); + } + } output_scope_log->set_schema_url(input_scope_log.first->GetSchemaURL()); } diff --git a/exporters/otlp/test/otlp_grpc_exporter_test.cc b/exporters/otlp/test/otlp_grpc_exporter_test.cc index 091cb0d0c4..3298e5390d 100644 --- a/exporters/otlp/test/otlp_grpc_exporter_test.cc +++ b/exporters/otlp/test/otlp_grpc_exporter_test.cc @@ -168,7 +168,7 @@ TEST_F(OtlpGrpcExporterTestPeer, ConfigFromEnv) const std::string cacert_str = "--begin and end fake cert--"; setenv("OTEL_EXPORTER_OTLP_CERTIFICATE_STRING", cacert_str.c_str(), 1); setenv("OTEL_EXPORTER_OTLP_SSL_ENABLE", "True", 1); - const std::string endpoint = "http://localhost:9999"; + const std::string endpoint = "https://localhost:9999"; setenv("OTEL_EXPORTER_OTLP_ENDPOINT", endpoint.c_str(), 1); setenv("OTEL_EXPORTER_OTLP_TIMEOUT", "20050ms", 1); setenv("OTEL_EXPORTER_OTLP_HEADERS", "k1=v1,k2=v2", 1); @@ -211,6 +211,76 @@ TEST_F(OtlpGrpcExporterTestPeer, ConfigFromEnv) } # endif +# ifndef NO_GETENV +// Test exporter configuration options with use_ssl_credentials +TEST_F(OtlpGrpcExporterTestPeer, ConfigHttpsSecureFromEnv) +{ + // https takes precedence over insecure + const std::string endpoint = "https://localhost:9999"; + setenv("OTEL_EXPORTER_OTLP_ENDPOINT", endpoint.c_str(), 1); + setenv("OTEL_EXPORTER_OTLP_TRACES_INSECURE", "true", 1); + + std::unique_ptr exporter(new OtlpGrpcExporter()); + EXPECT_EQ(GetOptions(exporter).use_ssl_credentials, true); + EXPECT_EQ(GetOptions(exporter).endpoint, endpoint); + + unsetenv("OTEL_EXPORTER_OTLP_ENDPOINT"); + unsetenv("OTEL_EXPORTER_OTLP_TRACES_INSECURE"); +} +# endif + +# ifndef NO_GETENV +// Test exporter configuration options with use_ssl_credentials +TEST_F(OtlpGrpcExporterTestPeer, ConfigHttpInsecureFromEnv) +{ + // http takes precedence over secure + const std::string endpoint = "http://localhost:9999"; + setenv("OTEL_EXPORTER_OTLP_ENDPOINT", endpoint.c_str(), 1); + setenv("OTEL_EXPORTER_OTLP_TRACES_INSECURE", "false", 1); + + std::unique_ptr exporter(new OtlpGrpcExporter()); + EXPECT_EQ(GetOptions(exporter).use_ssl_credentials, false); + EXPECT_EQ(GetOptions(exporter).endpoint, endpoint); + + unsetenv("OTEL_EXPORTER_OTLP_ENDPOINT"); + unsetenv("OTEL_EXPORTER_OTLP_TRACES_INSECURE"); +} +# endif + +# ifndef NO_GETENV +// Test exporter configuration options with use_ssl_credentials +TEST_F(OtlpGrpcExporterTestPeer, ConfigUnknownSecureFromEnv) +{ + const std::string endpoint = "localhost:9999"; + setenv("OTEL_EXPORTER_OTLP_ENDPOINT", endpoint.c_str(), 1); + setenv("OTEL_EXPORTER_OTLP_TRACES_INSECURE", "false", 1); + + std::unique_ptr exporter(new OtlpGrpcExporter()); + EXPECT_EQ(GetOptions(exporter).use_ssl_credentials, true); + EXPECT_EQ(GetOptions(exporter).endpoint, endpoint); + + unsetenv("OTEL_EXPORTER_OTLP_ENDPOINT"); + unsetenv("OTEL_EXPORTER_OTLP_TRACES_INSECURE"); +} +# endif + +# ifndef NO_GETENV +// Test exporter configuration options with use_ssl_credentials +TEST_F(OtlpGrpcExporterTestPeer, ConfigUnknownInsecureFromEnv) +{ + const std::string endpoint = "localhost:9999"; + setenv("OTEL_EXPORTER_OTLP_ENDPOINT", endpoint.c_str(), 1); + setenv("OTEL_EXPORTER_OTLP_TRACES_INSECURE", "true", 1); + + std::unique_ptr exporter(new OtlpGrpcExporter()); + EXPECT_EQ(GetOptions(exporter).use_ssl_credentials, false); + EXPECT_EQ(GetOptions(exporter).endpoint, endpoint); + + unsetenv("OTEL_EXPORTER_OTLP_ENDPOINT"); + unsetenv("OTEL_EXPORTER_OTLP_TRACES_INSECURE"); +} +# endif + } // namespace otlp } // namespace exporter OPENTELEMETRY_END_NAMESPACE diff --git a/exporters/otlp/test/otlp_grpc_log_record_exporter_test.cc b/exporters/otlp/test/otlp_grpc_log_record_exporter_test.cc index f87b5bf2d7..450bebc218 100644 --- a/exporters/otlp/test/otlp_grpc_log_record_exporter_test.cc +++ b/exporters/otlp/test/otlp_grpc_log_record_exporter_test.cc @@ -136,7 +136,8 @@ TEST_F(OtlpGrpcLogRecordExporterTestPeer, ExportIntegrationTest) opentelemetry::trace::SpanId span_id{span_id_bin}; const std::string schema_url{"https://opentelemetry.io/schemas/1.11.0"}; - auto logger = provider->GetLogger("test", "", "opentelelemtry_library", "", schema_url); + auto logger = provider->GetLogger("test", "opentelelemtry_library", "", schema_url, true, + {{"scope_key1", "scope_value"}, {"scope_key2", 2}}); std::unordered_map attributes; attributes["service.name"] = "unit_test_service"; attributes["tenant.id"] = "test_user"; @@ -153,9 +154,10 @@ TEST_F(OtlpGrpcLogRecordExporterTestPeer, ExportIntegrationTest) attributes["vec_uint64_value"] = attribute_storage_uint64_value; attributes["vec_double_value"] = attribute_storage_double_value; attributes["vec_string_value"] = attribute_storage_string_value; - logger->Log(opentelemetry::logs::Severity::kInfo, "Log message", attributes, trace_id, span_id, - opentelemetry::trace::TraceFlags{opentelemetry::trace::TraceFlags::kIsSampled}, - std::chrono::system_clock::now()); + logger->EmitLogRecord( + opentelemetry::logs::Severity::kInfo, "Log message", attributes, trace_id, span_id, + opentelemetry::trace::TraceFlags{opentelemetry::trace::TraceFlags::kIsSampled}, + std::chrono::system_clock::now()); } } // namespace otlp diff --git a/exporters/otlp/test/otlp_http_exporter_test.cc b/exporters/otlp/test/otlp_http_exporter_test.cc index d7d53d5839..007cd56249 100644 --- a/exporters/otlp/test/otlp_http_exporter_test.cc +++ b/exporters/otlp/test/otlp_http_exporter_test.cc @@ -59,7 +59,21 @@ OtlpHttpClientOptions MakeOtlpHttpClientOptions(HttpRequestContentType content_t options.http_headers.insert( std::make_pair("Custom-Header-Key", "Custom-Header-Value")); OtlpHttpClientOptions otlp_http_client_options( - options.url, options.content_type, options.json_bytes_mapping, options.use_json_name, + options.url, +# ifdef ENABLE_OTLP_HTTP_SSL_PREVIEW + false, /* ssl_insecure_skip_verify */ + "", /* ssl_ca_cert_path */ "", /* ssl_ca_cert_string */ + "", /* ssl_client_key_path */ + "", /* ssl_client_key_string */ "", /* ssl_client_cert_path */ + "", /* ssl_client_cert_string */ +# endif /* ENABLE_OTLP_HTTP_SSL_PREVIEW */ +# ifdef ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW + "", /* ssl_min_tls */ + "", /* ssl_max_tls */ + "", /* ssl_cipher */ + "", /* ssl_cipher_suite */ +# endif /* ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW */ + options.content_type, options.json_bytes_mapping, options.use_json_name, options.console_debug, options.timeout, options.http_headers); if (!async_mode) { @@ -557,7 +571,7 @@ TEST_F(OtlpHttpExporterTestPeer, ConfigFromTracesEnv) { const std::string url = "http://localhost:9999/v1/traces"; setenv("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", url.c_str(), 1); - setenv("OTEL_EXPORTER_OTLP_TIMEOUT", "20s", 1); + setenv("OTEL_EXPORTER_OTLP_TRACES_TIMEOUT", "1eternity", 1); setenv("OTEL_EXPORTER_OTLP_HEADERS", "k1=v1,k2=v2", 1); setenv("OTEL_EXPORTER_OTLP_TRACES_HEADERS", "k1=v3,k1=v4", 1); @@ -565,7 +579,7 @@ TEST_F(OtlpHttpExporterTestPeer, ConfigFromTracesEnv) EXPECT_EQ(GetOptions(exporter).url, url); EXPECT_EQ( GetOptions(exporter).timeout.count(), - std::chrono::duration_cast(std::chrono::seconds{20}) + std::chrono::duration_cast(std::chrono::seconds{10}) .count()); EXPECT_EQ(GetOptions(exporter).http_headers.size(), 3); { @@ -588,7 +602,7 @@ TEST_F(OtlpHttpExporterTestPeer, ConfigFromTracesEnv) } unsetenv("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"); - unsetenv("OTEL_EXPORTER_OTLP_TIMEOUT"); + unsetenv("OTEL_EXPORTER_OTLP_TRACES_TIMEOUT"); unsetenv("OTEL_EXPORTER_OTLP_HEADERS"); unsetenv("OTEL_EXPORTER_OTLP_TRACES_HEADERS"); } diff --git a/exporters/otlp/test/otlp_http_log_record_exporter_test.cc b/exporters/otlp/test/otlp_http_log_record_exporter_test.cc index c3fc69231a..aa55e7fc7c 100644 --- a/exporters/otlp/test/otlp_http_log_record_exporter_test.cc +++ b/exporters/otlp/test/otlp_http_log_record_exporter_test.cc @@ -60,7 +60,21 @@ OtlpHttpClientOptions MakeOtlpHttpClientOptions(HttpRequestContentType content_t options.http_headers.insert( std::make_pair("Custom-Header-Key", "Custom-Header-Value")); OtlpHttpClientOptions otlp_http_client_options( - options.url, options.content_type, options.json_bytes_mapping, options.use_json_name, + options.url, +# ifdef ENABLE_OTLP_HTTP_SSL_PREVIEW + false, /* ssl_insecure_skip_verify */ + "", /* ssl_ca_cert_path */ "", /* ssl_ca_cert_string */ + "", /* ssl_client_key_path */ + "", /* ssl_client_key_string */ "", /* ssl_client_cert_path */ + "", /* ssl_client_cert_string */ +# endif /* ENABLE_OTLP_HTTP_SSL_PREVIEW */ +# ifdef ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW + "", /* ssl_min_tls */ + "", /* ssl_max_tls */ + "", /* ssl_cipher */ + "", /* ssl_cipher_suite */ +# endif /* ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW */ + options.content_type, options.json_bytes_mapping, options.use_json_name, options.console_debug, options.timeout, options.http_headers); if (!async_mode) { @@ -129,7 +143,8 @@ class OtlpHttpLogRecordExporterTestPeer : public ::testing::Test opentelemetry::trace::SpanId span_id{span_id_bin}; const std::string schema_url{"https://opentelemetry.io/schemas/1.2.0"}; - auto logger = provider->GetLogger("test", "", "opentelelemtry_library", "", schema_url); + auto logger = provider->GetLogger("test", "opentelelemtry_library", "", schema_url, true, + {{"scope_key1", "scope_value"}, {"scope_key2", 2}}); trace_id.ToLowerBase16(MakeSpan(trace_id_hex)); report_trace_id.assign(trace_id_hex, sizeof(trace_id_hex)); @@ -147,6 +162,7 @@ class OtlpHttpLogRecordExporterTestPeer : public ::testing::Test nlohmann::json::parse(mock_session->GetRequest()->body_, nullptr, false); auto resource_logs = *check_json["resource_logs"].begin(); auto scope_logs = *resource_logs["scope_logs"].begin(); + auto scope = scope_logs["scope"]; auto log = *scope_logs["log_records"].begin(); auto received_trace_id = log["trace_id"].get(); auto received_span_id = log["span_id"].get(); @@ -161,29 +177,47 @@ class OtlpHttpLogRecordExporterTestPeer : public ::testing::Test EXPECT_EQ("Custom-Header-Value", custom_header->second); } + bool check_scope_attribute = false; + auto scope_attributes = scope["attributes"]; + for (auto &attribute : scope_attributes) + { + if (!attribute.is_object()) + { + continue; + } + if ("scope_key1" == attribute["key"]) + { + check_scope_attribute = true; + EXPECT_EQ("scope_value", attribute["value"]["string_value"].get()); + } + } + ASSERT_TRUE(check_scope_attribute); + http_client::nosend::Response response; response.Finish(*callback.get()); }); - logger->Log(opentelemetry::logs::Severity::kInfo, "Log message", - {{"service.name", "unit_test_service"}, - {"tenant.id", "test_user"}, - {"bool_value", true}, - {"int32_value", static_cast(1)}, - {"uint32_value", static_cast(2)}, - {"int64_value", static_cast(0x1100000000LL)}, - {"uint64_value", static_cast(0x1200000000ULL)}, - {"double_value", static_cast(3.1)}, - {"vec_bool_value", attribute_storage_bool_value}, - {"vec_int32_value", attribute_storage_int32_value}, - {"vec_uint32_value", attribute_storage_uint32_value}, - {"vec_int64_value", attribute_storage_int64_value}, - {"vec_uint64_value", attribute_storage_uint64_value}, - {"vec_double_value", attribute_storage_double_value}, - {"vec_string_value", attribute_storage_string_value}}, - trace_id, span_id, - opentelemetry::trace::TraceFlags{opentelemetry::trace::TraceFlags::kIsSampled}, - std::chrono::system_clock::now()); + logger->EmitLogRecord( + opentelemetry::logs::Severity::kInfo, "Log message", + opentelemetry::common::MakeAttributes( + {{"service.name", "unit_test_service"}, + {"tenant.id", "test_user"}, + {"bool_value", true}, + {"int32_value", static_cast(1)}, + {"uint32_value", static_cast(2)}, + {"int64_value", static_cast(0x1100000000LL)}, + {"uint64_value", static_cast(0x1200000000ULL)}, + {"double_value", static_cast(3.1)}, + {"vec_bool_value", attribute_storage_bool_value}, + {"vec_int32_value", attribute_storage_int32_value}, + {"vec_uint32_value", attribute_storage_uint32_value}, + {"vec_int64_value", attribute_storage_int64_value}, + {"vec_uint64_value", attribute_storage_uint64_value}, + {"vec_double_value", attribute_storage_double_value}, + {"vec_string_value", attribute_storage_string_value}}), + trace_id, span_id, + opentelemetry::trace::TraceFlags{opentelemetry::trace::TraceFlags::kIsSampled}, + std::chrono::system_clock::now()); provider->ForceFlush(); } @@ -226,7 +260,8 @@ class OtlpHttpLogRecordExporterTestPeer : public ::testing::Test opentelemetry::trace::SpanId span_id{span_id_bin}; const std::string schema_url{"https://opentelemetry.io/schemas/1.2.0"}; - auto logger = provider->GetLogger("test", "", "opentelelemtry_library", "1.2.0", schema_url); + auto logger = provider->GetLogger("test", "opentelelemtry_library", "1.2.0", schema_url, true, + {{"scope_key1", "scope_value"}, {"scope_key2", 2}}); trace_id.ToLowerBase16(MakeSpan(trace_id_hex)); report_trace_id.assign(trace_id_hex, sizeof(trace_id_hex)); @@ -265,6 +300,22 @@ class OtlpHttpLogRecordExporterTestPeer : public ::testing::Test EXPECT_EQ("Custom-Header-Value", custom_header->second); } + bool check_scope_attribute = false; + auto scope_attributes = scope["attributes"]; + for (auto &attribute : scope_attributes) + { + if (!attribute.is_object()) + { + continue; + } + if ("scope_key1" == attribute["key"]) + { + check_scope_attribute = true; + EXPECT_EQ("scope_value", attribute["value"]["string_value"].get()); + } + } + ASSERT_TRUE(check_scope_attribute); + // let the otlp_http_client to continue std::thread async_finish{[callback]() { std::this_thread::sleep_for(std::chrono::milliseconds(100)); @@ -274,25 +325,27 @@ class OtlpHttpLogRecordExporterTestPeer : public ::testing::Test async_finish.detach(); }); - logger->Log(opentelemetry::logs::Severity::kInfo, "Log message", - {{"service.name", "unit_test_service"}, - {"tenant.id", "test_user"}, - {"bool_value", true}, - {"int32_value", static_cast(1)}, - {"uint32_value", static_cast(2)}, - {"int64_value", static_cast(0x1100000000LL)}, - {"uint64_value", static_cast(0x1200000000ULL)}, - {"double_value", static_cast(3.1)}, - {"vec_bool_value", attribute_storage_bool_value}, - {"vec_int32_value", attribute_storage_int32_value}, - {"vec_uint32_value", attribute_storage_uint32_value}, - {"vec_int64_value", attribute_storage_int64_value}, - {"vec_uint64_value", attribute_storage_uint64_value}, - {"vec_double_value", attribute_storage_double_value}, - {"vec_string_value", attribute_storage_string_value}}, - trace_id, span_id, - opentelemetry::trace::TraceFlags{opentelemetry::trace::TraceFlags::kIsSampled}, - std::chrono::system_clock::now()); + logger->EmitLogRecord( + opentelemetry::logs::Severity::kInfo, "Log message", + opentelemetry::common::MakeAttributes( + {{"service.name", "unit_test_service"}, + {"tenant.id", "test_user"}, + {"bool_value", true}, + {"int32_value", static_cast(1)}, + {"uint32_value", static_cast(2)}, + {"int64_value", static_cast(0x1100000000LL)}, + {"uint64_value", static_cast(0x1200000000ULL)}, + {"double_value", static_cast(3.1)}, + {"vec_bool_value", attribute_storage_bool_value}, + {"vec_int32_value", attribute_storage_int32_value}, + {"vec_uint32_value", attribute_storage_uint32_value}, + {"vec_int64_value", attribute_storage_int64_value}, + {"vec_uint64_value", attribute_storage_uint64_value}, + {"vec_double_value", attribute_storage_double_value}, + {"vec_string_value", attribute_storage_string_value}}), + trace_id, span_id, + opentelemetry::trace::TraceFlags{opentelemetry::trace::TraceFlags::kIsSampled}, + std::chrono::system_clock::now()); provider->ForceFlush(); } @@ -332,7 +385,8 @@ class OtlpHttpLogRecordExporterTestPeer : public ::testing::Test opentelemetry::trace::SpanId span_id{span_id_bin}; const std::string schema_url{"https://opentelemetry.io/schemas/1.2.0"}; - auto logger = provider->GetLogger("test", "", "opentelelemtry_library", "1.2.0", schema_url); + auto logger = provider->GetLogger("test", "opentelelemtry_library", "1.2.0", schema_url, true, + {{"scope_key1", "scope_value"}, {"scope_key2", 2}}); report_trace_id.assign(reinterpret_cast(trace_id_bin), sizeof(trace_id_bin)); report_span_id.assign(reinterpret_cast(span_id_bin), sizeof(span_id_bin)); @@ -366,31 +420,44 @@ class OtlpHttpLogRecordExporterTestPeer : public ::testing::Test } ASSERT_TRUE(check_service_name); + bool check_scope_attribute = false; + for (auto &attribute : scope_log.scope().attributes()) + { + if ("scope_key1" == attribute.key()) + { + check_scope_attribute = true; + EXPECT_EQ("scope_value", attribute.value().string_value()); + } + } + ASSERT_TRUE(check_scope_attribute); + // let the otlp_http_client to continue http_client::nosend::Response response; response.Finish(*callback.get()); }); - logger->Log(opentelemetry::logs::Severity::kInfo, "Log message", - {{"service.name", "unit_test_service"}, - {"tenant.id", "test_user"}, - {"bool_value", true}, - {"int32_value", static_cast(1)}, - {"uint32_value", static_cast(2)}, - {"int64_value", static_cast(0x1100000000LL)}, - {"uint64_value", static_cast(0x1200000000ULL)}, - {"double_value", static_cast(3.1)}, - {"vec_bool_value", attribute_storage_bool_value}, - {"vec_int32_value", attribute_storage_int32_value}, - {"vec_uint32_value", attribute_storage_uint32_value}, - {"vec_int64_value", attribute_storage_int64_value}, - {"vec_uint64_value", attribute_storage_uint64_value}, - {"vec_double_value", attribute_storage_double_value}, - {"vec_string_value", attribute_storage_string_value}}, - trace_id, span_id, - opentelemetry::trace::TraceFlags{opentelemetry::trace::TraceFlags::kIsSampled}, - std::chrono::system_clock::now()); + logger->EmitLogRecord( + opentelemetry::logs::Severity::kInfo, "Log message", + opentelemetry::common::MakeAttributes( + {{"service.name", "unit_test_service"}, + {"tenant.id", "test_user"}, + {"bool_value", true}, + {"int32_value", static_cast(1)}, + {"uint32_value", static_cast(2)}, + {"int64_value", static_cast(0x1100000000LL)}, + {"uint64_value", static_cast(0x1200000000ULL)}, + {"double_value", static_cast(3.1)}, + {"vec_bool_value", attribute_storage_bool_value}, + {"vec_int32_value", attribute_storage_int32_value}, + {"vec_uint32_value", attribute_storage_uint32_value}, + {"vec_int64_value", attribute_storage_int64_value}, + {"vec_uint64_value", attribute_storage_uint64_value}, + {"vec_double_value", attribute_storage_double_value}, + {"vec_string_value", attribute_storage_string_value}}), + trace_id, span_id, + opentelemetry::trace::TraceFlags{opentelemetry::trace::TraceFlags::kIsSampled}, + std::chrono::system_clock::now()); provider->ForceFlush(); } @@ -431,7 +498,8 @@ class OtlpHttpLogRecordExporterTestPeer : public ::testing::Test opentelemetry::trace::SpanId span_id{span_id_bin}; const std::string schema_url{"https://opentelemetry.io/schemas/1.2.0"}; - auto logger = provider->GetLogger("test", "", "opentelelemtry_library", "", schema_url); + auto logger = provider->GetLogger("test", "opentelelemtry_library", "", schema_url, true, + {{"scope_key1", "scope_value"}, {"scope_key2", 2}}); report_trace_id.assign(reinterpret_cast(trace_id_bin), sizeof(trace_id_bin)); report_span_id.assign(reinterpret_cast(span_id_bin), sizeof(span_id_bin)); @@ -440,12 +508,13 @@ class OtlpHttpLogRecordExporterTestPeer : public ::testing::Test auto mock_session = std::static_pointer_cast(no_send_client->session_); EXPECT_CALL(*mock_session, SendRequest) - .WillOnce([&mock_session, report_trace_id, report_span_id]( + .WillOnce([&mock_session, report_trace_id, report_span_id, schema_url]( std::shared_ptr callback) { opentelemetry::proto::collector::logs::v1::ExportLogsServiceRequest request_body; request_body.ParseFromArray(&mock_session->GetRequest()->body_[0], static_cast(mock_session->GetRequest()->body_.size())); - auto received_log = request_body.resource_logs(0).scope_logs(0).log_records(0); + auto &scope_log = request_body.resource_logs(0).scope_logs(0); + auto received_log = scope_log.log_records(0); EXPECT_EQ(received_log.trace_id(), report_trace_id); EXPECT_EQ(received_log.span_id(), report_span_id); EXPECT_EQ("Log message", received_log.body().string_value()); @@ -461,6 +530,20 @@ class OtlpHttpLogRecordExporterTestPeer : public ::testing::Test } ASSERT_TRUE(check_service_name); + auto &scope = scope_log.scope(); + EXPECT_EQ(scope.name(), "opentelelemtry_library"); + EXPECT_EQ(scope_log.schema_url(), schema_url); + bool check_scope_attribute = false; + for (auto &attribute : scope.attributes()) + { + if ("scope_key1" == attribute.key()) + { + check_scope_attribute = true; + EXPECT_EQ("scope_value", attribute.value().string_value()); + } + } + ASSERT_TRUE(check_scope_attribute); + // let the otlp_http_client to continue std::thread async_finish{[callback]() { @@ -471,25 +554,27 @@ class OtlpHttpLogRecordExporterTestPeer : public ::testing::Test async_finish.detach(); }); - logger->Log(opentelemetry::logs::Severity::kInfo, "Log message", - {{"service.name", "unit_test_service"}, - {"tenant.id", "test_user"}, - {"bool_value", true}, - {"int32_value", static_cast(1)}, - {"uint32_value", static_cast(2)}, - {"int64_value", static_cast(0x1100000000LL)}, - {"uint64_value", static_cast(0x1200000000ULL)}, - {"double_value", static_cast(3.1)}, - {"vec_bool_value", attribute_storage_bool_value}, - {"vec_int32_value", attribute_storage_int32_value}, - {"vec_uint32_value", attribute_storage_uint32_value}, - {"vec_int64_value", attribute_storage_int64_value}, - {"vec_uint64_value", attribute_storage_uint64_value}, - {"vec_double_value", attribute_storage_double_value}, - {"vec_string_value", attribute_storage_string_value}}, - trace_id, span_id, - opentelemetry::trace::TraceFlags{opentelemetry::trace::TraceFlags::kIsSampled}, - std::chrono::system_clock::now()); + logger->EmitLogRecord( + opentelemetry::logs::Severity::kInfo, "Log message", + opentelemetry::common::MakeAttributes( + {{"service.name", "unit_test_service"}, + {"tenant.id", "test_user"}, + {"bool_value", true}, + {"int32_value", static_cast(1)}, + {"uint32_value", static_cast(2)}, + {"int64_value", static_cast(0x1100000000LL)}, + {"uint64_value", static_cast(0x1200000000ULL)}, + {"double_value", static_cast(3.1)}, + {"vec_bool_value", attribute_storage_bool_value}, + {"vec_int32_value", attribute_storage_int32_value}, + {"vec_uint32_value", attribute_storage_uint32_value}, + {"vec_int64_value", attribute_storage_int64_value}, + {"vec_uint64_value", attribute_storage_uint64_value}, + {"vec_double_value", attribute_storage_double_value}, + {"vec_string_value", attribute_storage_string_value}}), + trace_id, span_id, + opentelemetry::trace::TraceFlags{opentelemetry::trace::TraceFlags::kIsSampled}, + std::chrono::system_clock::now()); provider->ForceFlush(); } @@ -608,7 +693,7 @@ TEST_F(OtlpHttpLogRecordExporterTestPeer, ConfigFromLogsEnv) { const std::string url = "http://localhost:9999/v1/logs"; setenv("OTEL_EXPORTER_OTLP_LOGS_ENDPOINT", url.c_str(), 1); - setenv("OTEL_EXPORTER_OTLP_TIMEOUT", "20s", 1); + setenv("OTEL_EXPORTER_OTLP_LOGS_TIMEOUT", "20s", 1); setenv("OTEL_EXPORTER_OTLP_HEADERS", "k1=v1,k2=v2", 1); setenv("OTEL_EXPORTER_OTLP_LOGS_HEADERS", "k1=v3,k1=v4", 1); @@ -639,14 +724,14 @@ TEST_F(OtlpHttpLogRecordExporterTestPeer, ConfigFromLogsEnv) } unsetenv("OTEL_EXPORTER_OTLP_LOGS_ENDPOINT"); - unsetenv("OTEL_EXPORTER_OTLP_TIMEOUT"); + unsetenv("OTEL_EXPORTER_OTLP_LOGS_TIMEOUT"); unsetenv("OTEL_EXPORTER_OTLP_HEADERS"); unsetenv("OTEL_EXPORTER_OTLP_LOGS_HEADERS"); } TEST_F(OtlpHttpLogRecordExporterTestPeer, DefaultEndpoint) { - EXPECT_EQ("http://localhost:4318/v1/logs", GetOtlpDefaultHttpLogEndpoint()); + EXPECT_EQ("http://localhost:4318/v1/logs", GetOtlpDefaultHttpLogsEndpoint()); EXPECT_EQ("http://localhost:4318/v1/traces", GetOtlpDefaultHttpEndpoint()); EXPECT_EQ("http://localhost:4317", GetOtlpDefaultGrpcEndpoint()); } diff --git a/exporters/otlp/test/otlp_http_metric_exporter_test.cc b/exporters/otlp/test/otlp_http_metric_exporter_test.cc index 54abb88511..27f4614157 100644 --- a/exporters/otlp/test/otlp_http_metric_exporter_test.cc +++ b/exporters/otlp/test/otlp_http_metric_exporter_test.cc @@ -63,7 +63,21 @@ OtlpHttpClientOptions MakeOtlpHttpClientOptions(HttpRequestContentType content_t options.http_headers.insert( std::make_pair("Custom-Header-Key", "Custom-Header-Value")); OtlpHttpClientOptions otlp_http_client_options( - options.url, options.content_type, options.json_bytes_mapping, options.use_json_name, + options.url, +#ifdef ENABLE_OTLP_HTTP_SSL_PREVIEW + false, /* ssl_insecure_skip_verify */ + "", /* ssl_ca_cert_path */ "", /* ssl_ca_cert_string */ + "", /* ssl_client_key_path */ + "", /* ssl_client_key_string */ "", /* ssl_client_cert_path */ + "", /* ssl_client_cert_string */ +#endif /* ENABLE_OTLP_HTTP_SSL_PREVIEW */ +#ifdef ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW + "", /* ssl_min_tls */ + "", /* ssl_max_tls */ + "", /* ssl_cipher */ + "", /* ssl_cipher_suite */ +#endif /* ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW */ + options.content_type, options.json_bytes_mapping, options.use_json_name, options.console_debug, options.timeout, options.http_headers); if (!async_mode) { @@ -895,7 +909,7 @@ TEST_F(OtlpHttpMetricExporterTestPeer, ConfigFromMetricsEnv) { const std::string url = "http://localhost:9999/v1/metrics"; setenv("OTEL_EXPORTER_OTLP_METRICS_ENDPOINT", url.c_str(), 1); - setenv("OTEL_EXPORTER_OTLP_TIMEOUT", "20s", 1); + setenv("OTEL_EXPORTER_OTLP_METRICS_TIMEOUT", "20s", 1); setenv("OTEL_EXPORTER_OTLP_HEADERS", "k1=v1,k2=v2", 1); setenv("OTEL_EXPORTER_OTLP_METRICS_HEADERS", "k1=v3,k1=v4", 1); @@ -926,7 +940,7 @@ TEST_F(OtlpHttpMetricExporterTestPeer, ConfigFromMetricsEnv) } unsetenv("OTEL_EXPORTER_OTLP_METRICS_ENDPOINT"); - unsetenv("OTEL_EXPORTER_OTLP_TIMEOUT"); + unsetenv("OTEL_EXPORTER_OTLP_METRICS_TIMEOUT"); unsetenv("OTEL_EXPORTER_OTLP_HEADERS"); unsetenv("OTEL_EXPORTER_OTLP_METRICS_HEADERS"); } diff --git a/exporters/otlp/test/otlp_metrics_serialization_test.cc b/exporters/otlp/test/otlp_metrics_serialization_test.cc index adc4f488b0..cc3781c66f 100644 --- a/exporters/otlp/test/otlp_metrics_serialization_test.cc +++ b/exporters/otlp/test/otlp_metrics_serialization_test.cc @@ -54,11 +54,11 @@ static metrics_sdk::MetricData CreateHistogramAggregationData() s_data_1.sum_ = 100.2; s_data_1.count_ = 22; s_data_1.counts_ = {2, 9, 4, 7}; - s_data_1.boundaries_ = std::list({0.0, 10.0, 20.0, 30.0}); + s_data_1.boundaries_ = std::vector({0.0, 10.0, 20.0, 30.0}); s_data_2.sum_ = 200.2; s_data_2.count_ = 20; s_data_2.counts_ = {0, 8, 5, 7}; - s_data_2.boundaries_ = std::list({0.0, 10.0, 20.0, 30.0}); + s_data_2.boundaries_ = std::vector({0.0, 10.0, 20.0, 30.0}); data.aggregation_temporality = metrics_sdk::AggregationTemporality::kCumulative; data.end_ts = opentelemetry::common::SystemTimestamp(std::chrono::system_clock::now()); diff --git a/exporters/prometheus/BUILD b/exporters/prometheus/BUILD index 832a6f8acc..a7fb7e5e8c 100644 --- a/exporters/prometheus/BUILD +++ b/exporters/prometheus/BUILD @@ -1,16 +1,5 @@ -# 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. +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 package(default_visibility = ["//visibility:public"]) @@ -96,6 +85,7 @@ cc_test( deps = [ ":prometheus_exporter", ":prometheus_test_helper", + "//sdk/src/metrics", "@com_google_googletest//:gtest_main", ], ) @@ -112,6 +102,7 @@ cc_test( deps = [ ":prometheus_collector", ":prometheus_test_helper", + "//sdk/src/metrics", "@com_google_googletest//:gtest_main", ], ) diff --git a/exporters/prometheus/CMakeLists.txt b/exporters/prometheus/CMakeLists.txt index 13fb7c9de0..1e6c79e376 100644 --- a/exporters/prometheus/CMakeLists.txt +++ b/exporters/prometheus/CMakeLists.txt @@ -1,16 +1,5 @@ -# 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. +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 include_directories(include) if(NOT TARGET prometheus-cpp::core) @@ -37,18 +26,21 @@ endif() target_link_libraries( opentelemetry_exporter_prometheus PUBLIC opentelemetry_metrics prometheus-cpp::pull prometheus-cpp::core) -install( - TARGETS ${PROMETHEUS_EXPORTER_TARGETS} - EXPORT "${PROJECT_NAME}-target" - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) -install( - DIRECTORY include/opentelemetry/exporters/prometheus - DESTINATION include/opentelemetry/exporters/ - FILES_MATCHING - PATTERN "*.h") +if(OPENTELEMETRY_INSTALL) + install( + TARGETS ${PROMETHEUS_EXPORTER_TARGETS} + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + install( + DIRECTORY include/opentelemetry/exporters/prometheus + DESTINATION include/opentelemetry/exporters/ + FILES_MATCHING + PATTERN "*.h") +endif() if(BUILD_TESTING) add_subdirectory(test) diff --git a/exporters/prometheus/include/opentelemetry/exporters/prometheus/collector.h b/exporters/prometheus/include/opentelemetry/exporters/prometheus/collector.h index 2e7489e983..46d270905b 100644 --- a/exporters/prometheus/include/opentelemetry/exporters/prometheus/collector.h +++ b/exporters/prometheus/include/opentelemetry/exporters/prometheus/collector.h @@ -10,6 +10,7 @@ #include #include #include "opentelemetry/exporters/prometheus/exporter_utils.h" +#include "opentelemetry/sdk/metrics/metric_reader.h" namespace prometheus_client = ::prometheus; @@ -30,7 +31,7 @@ class PrometheusCollector : public prometheus_client::Collectable * This constructor initializes the collection for metrics to export * in this class with default capacity */ - explicit PrometheusCollector(size_t max_collection_size = 2048); + explicit PrometheusCollector(sdk::metrics::MetricReader *reader); /** * Collects all metrics data from metricsToCollect collection. @@ -39,41 +40,8 @@ class PrometheusCollector : public prometheus_client::Collectable */ std::vector Collect() const override; - /** - * This function is called by export() function and add the collection of - * records to the metricsToCollect collection - * - * @param records a collection of records to add to the metricsToCollect collection - */ - void AddMetricData(const sdk::metrics::ResourceMetrics &data); - - /** - * Get the current collection in the collector. - * - * @return the current metricsToCollect collection - */ - std::vector> &GetCollection(); - - /** - * Gets the maximum size of the collection. - * - * @return max collection size - */ - int GetMaxCollectionSize() const; - private: - /** - * Collection of metrics data from the export() function, and to be export - * to user when they send a pull request. This collection is a pointer - * to a collection so Collect() is able to clear the collection, even - * though it is a const function. - */ - mutable std::vector> metrics_to_collect_; - - /** - * Maximum size of the metricsToCollect collection. - */ - size_t max_collection_size_; + sdk::metrics::MetricReader *reader_; /* * Lock when operating the metricsToCollect collection diff --git a/exporters/prometheus/include/opentelemetry/exporters/prometheus/exporter.h b/exporters/prometheus/include/opentelemetry/exporters/prometheus/exporter.h index ab05fc71db..fe3c603e8a 100644 --- a/exporters/prometheus/include/opentelemetry/exporters/prometheus/exporter.h +++ b/exporters/prometheus/include/opentelemetry/exporters/prometheus/exporter.h @@ -12,7 +12,7 @@ #include "opentelemetry/exporters/prometheus/collector.h" #include "opentelemetry/nostd/span.h" #include "opentelemetry/sdk/common/env_variables.h" -#include "opentelemetry/sdk/metrics/push_metric_exporter.h" +#include "opentelemetry/sdk/metrics/metric_reader.h" #include "opentelemetry/version.h" /** @@ -33,8 +33,11 @@ inline const std::string GetPrometheusDefaultHttpEndpoint() constexpr char kPrometheusEndpointEnv[] = "PROMETHEUS_EXPORTER_ENDPOINT"; constexpr char kPrometheusEndpointDefault[] = "localhost:9464"; - auto endpoint = opentelemetry::sdk::common::GetEnvironmentVariable(kPrometheusEndpointEnv); - return endpoint.size() ? endpoint : kPrometheusEndpointDefault; + std::string endpoint; + + auto exists = + opentelemetry::sdk::common::GetStringEnvironmentVariable(kPrometheusEndpointEnv, endpoint); + return exists ? endpoint : kPrometheusEndpointDefault; } /** @@ -46,7 +49,7 @@ struct PrometheusExporterOptions std::string url = GetPrometheusDefaultHttpEndpoint(); }; -class PrometheusExporter : public sdk::metrics::PushMetricExporter +class PrometheusExporter : public sdk::metrics::MetricReader { public: /** @@ -56,54 +59,12 @@ class PrometheusExporter : public sdk::metrics::PushMetricExporter */ PrometheusExporter(const PrometheusExporterOptions &options); - /** - * Get the AggregationTemporality for Prometheus exporter - * - * @return AggregationTemporality - */ sdk::metrics::AggregationTemporality GetAggregationTemporality( sdk::metrics::InstrumentType instrument_type) const noexcept override; - /** - * Exports a batch of Metric Records. - * @param records: a collection of records to export - * @return: returns a ReturnCode detailing a success, or type of failure - */ - sdk::common::ExportResult Export(const sdk::metrics::ResourceMetrics &data) noexcept override; - - /** - * Force flush the exporter. - */ - bool ForceFlush( - std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept override; - - /** - * Shuts down the exporter and does cleanup. - * Since Prometheus is a pull based interface, - * we cannot serve data remaining in the intermediate - * collection to to client an HTTP request being sent, - * so we flush the data. - */ - bool Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override; - - /** - * @return: returns a shared_ptr to - * the PrometheusCollector instance - */ - std::shared_ptr &GetCollector(); - - /** - * @return: Gets the shutdown status of the exporter - */ - bool IsShutdown() const; - private: // The configuration options associated with this exporter. const PrometheusExporterOptions options_; - /** - * exporter shutdown status - */ - bool is_shutdown_; /** * Pointer to a @@ -117,16 +78,11 @@ class PrometheusExporter : public sdk::metrics::PushMetricExporter */ std::unique_ptr<::prometheus::Exposer> exposer_; - /** - * friend class for testing - */ - friend class PrometheusExporterTest; + bool OnForceFlush(std::chrono::microseconds timeout) noexcept override; - /** - * PrometheusExporter constructor with no parameters - * Used for testing only - */ - PrometheusExporter(); + bool OnShutDown(std::chrono::microseconds timeout) noexcept override; + + void OnInitialized() noexcept override; }; } // namespace metrics } // namespace exporter diff --git a/exporters/prometheus/include/opentelemetry/exporters/prometheus/exporter_utils.h b/exporters/prometheus/include/opentelemetry/exporters/prometheus/exporter_utils.h index d85d6d8a0c..e602c87737 100644 --- a/exporters/prometheus/include/opentelemetry/exporters/prometheus/exporter_utils.h +++ b/exporters/prometheus/include/opentelemetry/exporters/prometheus/exporter_utils.h @@ -29,7 +29,7 @@ class PrometheusExporterUtils * @return a collection of translated metrics that is acceptable by Prometheus */ static std::vector<::prometheus::MetricFamily> TranslateToPrometheus( - const std::vector> &data); + const sdk::metrics::ResourceMetrics &data); private: /** @@ -67,7 +67,7 @@ class PrometheusExporterUtils */ template static void SetData(std::vector values, - const std::list &boundaries, + const std::vector &boundaries, const std::vector &counts, const opentelemetry::sdk::metrics::PointAttributes &labels, std::chrono::nanoseconds time, @@ -104,7 +104,7 @@ class PrometheusExporterUtils */ template static void SetValue(std::vector values, - const std::list &boundaries, + const std::vector &boundaries, const std::vector &counts, ::prometheus::ClientMetric *metric); }; diff --git a/exporters/prometheus/src/collector.cc b/exporters/prometheus/src/collector.cc index 07dd40da98..29c0bc8db2 100644 --- a/exporters/prometheus/src/collector.cc +++ b/exporters/prometheus/src/collector.cc @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "opentelemetry/exporters/prometheus/collector.h" +#include "opentelemetry/sdk/common/global_log_handler.h" namespace metric_sdk = opentelemetry::sdk::metrics; @@ -16,9 +17,7 @@ namespace metrics * This constructor initializes the collection for metrics to export * in this class with default capacity */ -PrometheusCollector::PrometheusCollector(size_t max_collection_size) - : max_collection_size_(max_collection_size) -{} +PrometheusCollector::PrometheusCollector(sdk::metrics::MetricReader *reader) : reader_(reader) {} /** * Collects all metrics data from metricsToCollect collection. @@ -27,59 +26,24 @@ PrometheusCollector::PrometheusCollector(size_t max_collection_size) */ std::vector PrometheusCollector::Collect() const { - this->collection_lock_.lock(); - if (metrics_to_collect_.empty()) + if (reader_->IsShutdown()) { - this->collection_lock_.unlock(); + OTEL_INTERNAL_LOG_WARN( + "[Prometheus Exporter] Collect: " + "Exporter is shutdown, can not invoke collect operation."); return {}; } + collection_lock_.lock(); std::vector result; - - // copy the intermediate collection, and then clear it - std::vector> copied_data; - copied_data.swap(metrics_to_collect_); - this->collection_lock_.unlock(); - - result = PrometheusExporterUtils::TranslateToPrometheus(copied_data); - return result; -} - -/** - * This function is called by export() function and add the collection of - * records to the metricsToCollect collection - * - * @param records a collection of records to add to the metricsToCollect collection - */ -void PrometheusCollector::AddMetricData(const sdk::metrics::ResourceMetrics &data) -{ - collection_lock_.lock(); - if (metrics_to_collect_.size() + 1 <= max_collection_size_) - { - // We can not use initializer lists here due to broken variadic capture on GCC 4.8.5 - metrics_to_collect_.emplace_back(new sdk::metrics::ResourceMetrics(data)); - } + reader_->Collect([&result](sdk::metrics::ResourceMetrics &metric_data) { + auto prometheus_metric_data = PrometheusExporterUtils::TranslateToPrometheus(metric_data); + for (auto &data : prometheus_metric_data) + result.emplace_back(data); + return true; + }); collection_lock_.unlock(); -} - -/** - * Get the current collection in the collector. - * - * @return the current metrics_to_collect collection - */ -std::vector> &PrometheusCollector::GetCollection() -{ - return metrics_to_collect_; -} - -/** - * Gets the maximum size of the collection. - * - * @return max collection size - */ -int PrometheusCollector::GetMaxCollectionSize() const -{ - return max_collection_size_; + return result; } } // namespace metrics diff --git a/exporters/prometheus/src/exporter.cc b/exporters/prometheus/src/exporter.cc index f220ebd7d7..7691e32f39 100644 --- a/exporters/prometheus/src/exporter.cc +++ b/exporters/prometheus/src/exporter.cc @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "opentelemetry/exporters/prometheus/exporter.h" +#include "opentelemetry/sdk/common/global_log_handler.h" OPENTELEMETRY_BEGIN_NAMESPACE @@ -14,24 +15,26 @@ namespace metrics * @param address: an address for an exposer that exposes * an HTTP endpoint for the exporter to connect to */ -PrometheusExporter::PrometheusExporter(const PrometheusExporterOptions &options) - : options_(options), is_shutdown_(false) +PrometheusExporter::PrometheusExporter(const PrometheusExporterOptions &options) : options_(options) { - exposer_ = std::unique_ptr<::prometheus::Exposer>(new ::prometheus::Exposer{options_.url}); - collector_ = std::shared_ptr(new PrometheusCollector); + try + { + exposer_ = std::unique_ptr<::prometheus::Exposer>(new ::prometheus::Exposer{options_.url}); + } + catch (const std::exception &ex) + { + exposer_.reset(nullptr); + OTEL_INTERNAL_LOG_ERROR("[Prometheus Exporter] " + << "Can't initialize prometheus exposer with endpoint: " << options_.url + << "\nError: " << ex.what()); + Shutdown(); // set MetricReader in shutdown state. + return; + } + collector_ = std::shared_ptr(new PrometheusCollector(this)); exposer_->RegisterCollectable(collector_); } -/** - * PrometheusExporter constructor with no parameters - * Used for testing only - */ -PrometheusExporter::PrometheusExporter() : is_shutdown_(false) -{ - collector_ = std::unique_ptr(new PrometheusCollector(3)); -} - sdk::metrics::AggregationTemporality PrometheusExporter::GetAggregationTemporality( sdk::metrics::InstrumentType /* instrument_type */) const noexcept { @@ -39,71 +42,19 @@ sdk::metrics::AggregationTemporality PrometheusExporter::GetAggregationTemporali return sdk::metrics::AggregationTemporality::kCumulative; } -/** - * Exports a batch of Metric Records. - * @param records: a collection of records to export - * @return: returns a ReturnCode detailing a success, or type of failure - */ -sdk::common::ExportResult PrometheusExporter::Export( - const sdk::metrics::ResourceMetrics &data) noexcept -{ - if (is_shutdown_) - { - return sdk::common::ExportResult::kFailure; - } - else if (collector_->GetCollection().size() + data.scope_metric_data_.size() > - (size_t)collector_->GetMaxCollectionSize()) - { - return sdk::common::ExportResult::kFailureFull; - } - else if (data.scope_metric_data_.empty()) - { - return sdk::common::ExportResult::kFailureInvalidArgument; - } - else - { - collector_->AddMetricData(data); - return sdk::common::ExportResult::kSuccess; - } - return sdk::common::ExportResult::kSuccess; -} - -bool PrometheusExporter::ForceFlush(std::chrono::microseconds /* timeout */) noexcept +bool PrometheusExporter::OnForceFlush(std::chrono::microseconds /* timeout */) noexcept { return true; } -/** - * Shuts down the exporter and does cleanup. - * Since Prometheus is a pull based interface, - * we cannot serve data remaining in the intermediate - * collection to to client an HTTP request being sent, - * so we flush the data. - */ -bool PrometheusExporter::Shutdown(std::chrono::microseconds /* timeout */) noexcept +bool PrometheusExporter::OnShutDown(std::chrono::microseconds /* timeout */) noexcept { - is_shutdown_ = true; + if (exposer_ != nullptr) + exposer_->RemoveCollectable(collector_); return true; - - collector_->GetCollection().clear(); } -/** - * @return: returns a shared_ptr to - * the PrometheusCollector instance - */ -std::shared_ptr &PrometheusExporter::GetCollector() -{ - return collector_; -} - -/** - * @return: Gets the shutdown status of the exporter - */ -bool PrometheusExporter::IsShutdown() const -{ - return is_shutdown_; -} +void PrometheusExporter::OnInitialized() noexcept {} } // namespace metrics } // namespace exporter diff --git a/exporters/prometheus/src/exporter_utils.cc b/exporters/prometheus/src/exporter_utils.cc index a8c648132e..451c34ff45 100644 --- a/exporters/prometheus/src/exporter_utils.cc +++ b/exporters/prometheus/src/exporter_utils.cc @@ -28,102 +28,93 @@ namespace metrics * @return a collection of translated metrics that is acceptable by Prometheus */ std::vector PrometheusExporterUtils::TranslateToPrometheus( - const std::vector> &data) + const sdk::metrics::ResourceMetrics &data) { - if (data.empty()) - { - return {}; - } // initialize output vector std::vector output; - // iterate through the vector and set result data into it - for (const auto &r : data) + for (const auto &instrumentation_info : data.scope_metric_data_) { - for (const auto &instrumentation_info : r->scope_metric_data_) + for (const auto &metric_data : instrumentation_info.metric_data_) { - for (const auto &metric_data : instrumentation_info.metric_data_) + auto origin_name = metric_data.instrument_descriptor.name_; + auto sanitized = SanitizeNames(origin_name); + prometheus_client::MetricFamily metric_family; + metric_family.name = sanitized; + metric_family.help = metric_data.instrument_descriptor.description_; + auto time = metric_data.start_ts.time_since_epoch(); + for (const auto &point_data_attr : metric_data.point_data_attr_) { - auto origin_name = metric_data.instrument_descriptor.name_; - auto sanitized = SanitizeNames(origin_name); - prometheus_client::MetricFamily metric_family; - metric_family.name = sanitized; - metric_family.help = metric_data.instrument_descriptor.description_; - auto time = metric_data.start_ts.time_since_epoch(); - for (const auto &point_data_attr : metric_data.point_data_attr_) + auto kind = getAggregationType(point_data_attr.point_data); + bool is_monotonic = true; + if (kind == sdk::metrics::AggregationType::kSum) + { + is_monotonic = + nostd::get(point_data_attr.point_data).is_monotonic_; + } + const prometheus_client::MetricType type = TranslateType(kind, is_monotonic); + metric_family.type = type; + if (type == prometheus_client::MetricType::Histogram) // Histogram + { + auto histogram_point_data = + nostd::get(point_data_attr.point_data); + auto boundaries = histogram_point_data.boundaries_; + auto counts = histogram_point_data.counts_; + double sum = 0.0; + if (nostd::holds_alternative(histogram_point_data.sum_)) + { + sum = nostd::get(histogram_point_data.sum_); + } + else + { + sum = nostd::get(histogram_point_data.sum_); + } + SetData(std::vector{sum, (double)histogram_point_data.count_}, boundaries, counts, + point_data_attr.attributes, time, &metric_family); + } + else if (type == prometheus_client::MetricType::Gauge) { - auto kind = getAggregationType(point_data_attr.point_data); - bool is_monotonic = true; - if (kind == sdk::metrics::AggregationType::kSum) + if (nostd::holds_alternative( + point_data_attr.point_data)) { - is_monotonic = - nostd::get(point_data_attr.point_data).is_monotonic_; + auto last_value_point_data = + nostd::get(point_data_attr.point_data); + std::vector values{last_value_point_data.value_}; + SetData(values, point_data_attr.attributes, type, time, &metric_family); } - const prometheus_client::MetricType type = TranslateType(kind, is_monotonic); - metric_family.type = type; - if (type == prometheus_client::MetricType::Histogram) // Histogram + else if (nostd::holds_alternative(point_data_attr.point_data)) { - auto histogram_point_data = - nostd::get(point_data_attr.point_data); - auto boundaries = histogram_point_data.boundaries_; - auto counts = histogram_point_data.counts_; - double sum = 0.0; - if (nostd::holds_alternative(histogram_point_data.sum_)) - { - sum = nostd::get(histogram_point_data.sum_); - } - else - { - sum = nostd::get(histogram_point_data.sum_); - } - SetData(std::vector{sum, (double)histogram_point_data.count_}, boundaries, - counts, point_data_attr.attributes, time, &metric_family); + auto sum_point_data = + nostd::get(point_data_attr.point_data); + std::vector values{sum_point_data.value_}; + SetData(values, point_data_attr.attributes, type, time, &metric_family); } - else if (type == prometheus_client::MetricType::Gauge) + else + { + OTEL_INTERNAL_LOG_WARN( + "[Prometheus Exporter] TranslateToPrometheus - " + "invalid LastValuePointData type"); + } + } + else // Counter, Untyped + { + if (nostd::holds_alternative(point_data_attr.point_data)) { - if (nostd::holds_alternative( - point_data_attr.point_data)) - { - auto last_value_point_data = - nostd::get(point_data_attr.point_data); - std::vector values{last_value_point_data.value_}; - SetData(values, point_data_attr.attributes, type, time, &metric_family); - } - else if (nostd::holds_alternative( - point_data_attr.point_data)) - { - auto sum_point_data = - nostd::get(point_data_attr.point_data); - std::vector values{sum_point_data.value_}; - SetData(values, point_data_attr.attributes, type, time, &metric_family); - } - else - { - OTEL_INTERNAL_LOG_WARN( - "[Prometheus Exporter] TranslateToPrometheus - " - "invalid LastValuePointData type"); - } + auto sum_point_data = + nostd::get(point_data_attr.point_data); + std::vector values{sum_point_data.value_}; + SetData(values, point_data_attr.attributes, type, time, &metric_family); } - else // Counter, Untyped + else { - if (nostd::holds_alternative(point_data_attr.point_data)) - { - auto sum_point_data = - nostd::get(point_data_attr.point_data); - std::vector values{sum_point_data.value_}; - SetData(values, point_data_attr.attributes, type, time, &metric_family); - } - else - { - OTEL_INTERNAL_LOG_WARN( - "[Prometheus Exporter] TranslateToPrometheus - " - "invalid SumPointData type"); - } + OTEL_INTERNAL_LOG_WARN( + "[Prometheus Exporter] TranslateToPrometheus - " + "invalid SumPointData type"); } } - output.emplace_back(metric_family); } + output.emplace_back(metric_family); } } return output; @@ -221,7 +212,7 @@ void PrometheusExporterUtils::SetData(std::vector values, */ template void PrometheusExporterUtils::SetData(std::vector values, - const std::list &boundaries, + const std::vector &boundaries, const std::vector &counts, const metric_sdk::PointAttributes &labels, std::chrono::nanoseconds time, @@ -340,7 +331,7 @@ void PrometheusExporterUtils::SetValue(std::vector values, */ template void PrometheusExporterUtils::SetValue(std::vector values, - const std::list &boundaries, + const std::vector &boundaries, const std::vector &counts, prometheus_client::ClientMetric *metric) { diff --git a/exporters/prometheus/test/CMakeLists.txt b/exporters/prometheus/test/CMakeLists.txt index 3180c00e0c..1ef890b27e 100644 --- a/exporters/prometheus/test/CMakeLists.txt +++ b/exporters/prometheus/test/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + foreach(testname exporter_test collector_test exporter_utils_test) add_executable(${testname} "${testname}.cc") target_link_libraries( diff --git a/exporters/prometheus/test/collector_test.cc b/exporters/prometheus/test/collector_test.cc index b6460761ed..d422c45c5b 100644 --- a/exporters/prometheus/test/collector_test.cc +++ b/exporters/prometheus/test/collector_test.cc @@ -1,352 +1,82 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +#include "opentelemetry/exporters/prometheus/collector.h" +#include "opentelemetry/metrics/meter_provider.h" +#include "opentelemetry/version.h" +#include "prometheus_test_helper.h" + #include #include #include #include -#include "opentelemetry/exporters/prometheus/collector.h" -#include "opentelemetry/version.h" -#include "prometheus_test_helper.h" - using opentelemetry::exporter::metrics::PrometheusCollector; -namespace metric_api = opentelemetry::metrics; -namespace metric_sdk = opentelemetry::sdk::metrics; +using opentelemetry::sdk::metrics::ResourceMetrics; +namespace metric_api = opentelemetry::metrics; +namespace metric_sdk = opentelemetry::sdk::metrics; +namespace metric_exporter = opentelemetry::exporter::metrics; -OPENTELEMETRY_BEGIN_NAMESPACE - -// ==================== Test for addMetricsData() function ====================== - -/** - * AddMetricData() should be able to successfully add a collection - * of SumPointData. It checks that the cumulative - * sum of updates to the aggregator of a record before and after AddMetricData() - * is called are equal. - */ -TEST(PrometheusCollector, AddMetricDataWithCounterRecordsSuccessfully) +class MockMetricProducer : public opentelemetry::sdk::metrics::MetricProducer { - PrometheusCollector collector; - - // construct a collection of records with CounterAggregators and double - auto data = CreateSumPointData(); - - // add records to collection - collector.AddMetricData(data); - - // Collection size should be the same as the size - // of the records collection passed to addMetricData() - ASSERT_EQ(collector.GetCollection().size(), 1); - - // check values of records created vs records from metricsToCollect, - // accessed by getCollection() +public: + MockMetricProducer(std::chrono::microseconds sleep_ms = std::chrono::microseconds::zero()) + : sleep_ms_{sleep_ms}, data_sent_size_(0) + {} - auto &&collector_data = collector.GetCollection(); - ASSERT_EQ(collector_data.at(0)->resource_, data.resource_); - for (auto &collector_d : collector_data) + bool Collect(nostd::function_ref callback) noexcept override { - for (uint32_t instrument_idx = 0; instrument_idx < collector_d->scope_metric_data_.size(); - ++instrument_idx) - { - ASSERT_EQ(collector_d->scope_metric_data_.at(instrument_idx).scope_, - data.scope_metric_data_.at(instrument_idx).scope_); - ASSERT_EQ(collector_d->scope_metric_data_.at(instrument_idx).metric_data_, - data.scope_metric_data_.at(instrument_idx).metric_data_); - } + std::this_thread::sleep_for(sleep_ms_); + data_sent_size_++; + ResourceMetrics data = CreateSumPointData(); + callback(data); + return true; } -} - -/** - * AddMetricData() should be able to successfully add a collection - * of HistogramPointData. It checks that the cumulative - * sum of updates to the aggregator of a record before and after AddMetricData() - * is called are equal. - */ -TEST(PrometheusCollector, AddMetricDataWithHistogramSuccessfully) -{ - PrometheusCollector collector; - - // construct a collection of records with CounterAggregators and double - auto data = CreateHistogramPointData(); - - // add records to collection - collector.AddMetricData(data); - // Collection size should be the same as the size - // of the records collection passed to addMetricData() - ASSERT_EQ(collector.GetCollection().size(), 1); + size_t GetDataCount() { return data_sent_size_; } - // check values of records created vs records from metricsToCollect, - // accessed by getCollection() +private: + std::chrono::microseconds sleep_ms_; + size_t data_sent_size_; +}; - auto &&collector_data = collector.GetCollection(); - ASSERT_EQ(collector_data.at(0)->resource_, data.resource_); - for (auto &collector_d : collector_data) +class MockMetricReader : public opentelemetry::sdk::metrics::MetricReader +{ +public: + opentelemetry::sdk::metrics::AggregationTemporality GetAggregationTemporality( + opentelemetry::sdk::metrics::InstrumentType /* instrument_type */) const noexcept override { - for (uint32_t instrument_idx = 0; instrument_idx < collector_d->scope_metric_data_.size(); - ++instrument_idx) - { - ASSERT_EQ(collector_d->scope_metric_data_.at(instrument_idx).scope_, - data.scope_metric_data_.at(instrument_idx).scope_); - ASSERT_EQ(collector_d->scope_metric_data_.at(instrument_idx).metric_data_, - data.scope_metric_data_.at(instrument_idx).metric_data_); - } + // Prometheus exporter only support Cumulative + return opentelemetry::sdk::metrics::AggregationTemporality::kCumulative; } -} - -/** - * AddMetricData() should be able to successfully add a collection - * of LastValuePointData. It checks that the cumulative - * sum of updates to the aggregator of a record before and after AddMetricData() - * is called are equal. - */ -TEST(PrometheusCollector, AddMetricDataWithLastValueSuccessfully) -{ - PrometheusCollector collector; - // construct a collection of records with CounterAggregators and double - auto data = CreateLastValuePointData(); +private: + bool OnForceFlush(std::chrono::microseconds /* timeout */) noexcept override { return true; } - // add records to collection - collector.AddMetricData(data); - - // Collection size should be the same as the size - // of the records collection passed to addMetricData() - ASSERT_EQ(collector.GetCollection().size(), 1); + bool OnShutDown(std::chrono::microseconds /* timeout */) noexcept override { return true; } - // check values of records created vs records from metricsToCollect, - // accessed by getCollection() + void OnInitialized() noexcept override {} +}; - auto &&collector_data = collector.GetCollection(); - ASSERT_EQ(collector_data.at(0)->resource_, data.resource_); - for (auto &collector_d : collector_data) - { - for (uint32_t instrument_idx = 0; instrument_idx < collector_d->scope_metric_data_.size(); - ++instrument_idx) - { - ASSERT_EQ(collector_d->scope_metric_data_.at(instrument_idx).scope_, - data.scope_metric_data_.at(instrument_idx).scope_); - ASSERT_EQ(collector_d->scope_metric_data_.at(instrument_idx).metric_data_, - data.scope_metric_data_.at(instrument_idx).metric_data_); - } - } -} +// ==================== Test for addMetricsData() function ====================== /** * AddMetricData() should be able to successfully add a collection - * of DropPointData. It checks that the cumulative + * of SumPointData. It checks that the cumulative * sum of updates to the aggregator of a record before and after AddMetricData() * is called are equal. */ -TEST(PrometheusCollector, AddMetricDataWithDropSuccessfully) +TEST(PrometheusCollector, BasicTests) { - PrometheusCollector collector; - - // construct a collection of records with CounterAggregators and double - auto data = CreateDropPointData(); - - // add records to collection - collector.AddMetricData(data); + MockMetricReader *reader = new MockMetricReader(); + MockMetricProducer *producer = new MockMetricProducer(); + reader->SetMetricProducer(producer); + PrometheusCollector collector(reader); + auto data = collector.Collect(); // Collection size should be the same as the size - // of the records collection passed to addMetricData() - ASSERT_EQ(collector.GetCollection().size(), 1); - - // check values of records created vs records from metricsToCollect, - // accessed by getCollection() - - auto &&collector_data = collector.GetCollection(); - ASSERT_EQ(collector_data.at(0)->resource_, data.resource_); - for (auto &collector_d : collector_data) - { - for (uint32_t instrument_idx = 0; instrument_idx < collector_d->scope_metric_data_.size(); - ++instrument_idx) - { - ASSERT_EQ(collector_d->scope_metric_data_.at(instrument_idx).scope_, - data.scope_metric_data_.at(instrument_idx).scope_); - ASSERT_EQ(collector_d->scope_metric_data_.at(instrument_idx).metric_data_, - data.scope_metric_data_.at(instrument_idx).metric_data_); - } - } -} - -TEST(PrometheusCollector, AddMetricDataDoesNotAddWithInsufficentSpace) -{ - PrometheusCollector collector; - - int max_collection_size = collector.GetMaxCollectionSize(); - - for (int count = 1; count <= max_collection_size; ++count) - { - collector.AddMetricData(CreateSumPointData()); - ASSERT_EQ(count, collector.GetCollection().size()); - } - - // Try adding one more collection of records again to - // metricsToCollect. - collector.AddMetricData(CreateSumPointData()); - - // Check that the number of records in metricsToCollect - // has not changed. - ASSERT_EQ(collector.GetCollection().size(), max_collection_size); + // of the records collection produced by MetricProducer. + ASSERT_EQ(data.size(), 1); + delete reader; + delete producer; } - -// ==================== Test for Constructor ====================== -TEST(PrometheusCollector, ConstructorInitializesCollector) -{ - PrometheusCollector collector; - - // current size should be 0, capacity should be set to default - ASSERT_EQ(collector.GetCollection().size(), 0); -} - -// ==================== Tests for collect() function ====================== - -/** - * When collector is initialized, the collection inside is should also be initialized - */ -TEST(PrometheusCollector, CollectInitializesMetricFamilyCollection) -{ - PrometheusCollector collector; - auto c1 = collector.Collect(); - ASSERT_EQ(c1.size(), 0); -} - -/** - * Collect function should collect all data and clear the intermediate collection - */ -TEST(PrometheusCollector, CollectClearsTheCollection) -{ - PrometheusCollector collector; - - // construct a collection to add metric records - collector.AddMetricData(CreateSumPointData()); - collector.AddMetricData(CreateSumPointData()); - - // the collection should not be empty now - ASSERT_EQ(collector.GetCollection().size(), 2); - - // don't care the collected result in this test - collector.Collect(); - - // after the collect() call, the collection should be empty - ASSERT_EQ(collector.GetCollection().size(), 0); -} - -/** - * Collected data should be already be parsed to Prometheus Metric format - */ -TEST(PrometheusCollector, CollectParsesDataToMetricFamily) -{ - PrometheusCollector collector; - - collector.AddMetricData(CreateSumPointData()); - - // the collection should not be empty now - ASSERT_EQ(collector.GetCollection().size(), 1); - auto collected = collector.Collect(); - - ASSERT_EQ(collected.size(), 1); - - auto metric_family = collected[0]; - - // Collect function really collects a vector of MetricFamily - ASSERT_EQ(metric_family.name, "library_name"); - ASSERT_EQ(metric_family.help, "description"); - ASSERT_EQ(metric_family.type, prometheus_client::MetricType::Counter); - ASSERT_EQ(metric_family.metric.size(), 2); - ASSERT_DOUBLE_EQ(metric_family.metric[0].counter.value, 10); -} - -/** - * Concurrency Test 1: After adding data concurrently, the intermediate collection should - * contain all data from all threads. - */ -TEST(PrometheusCollector, ConcurrencyAddingRecords) -{ - PrometheusCollector collector; - - std::thread first(&PrometheusCollector::AddMetricData, std::ref(collector), CreateSumPointData()); - std::thread second(&PrometheusCollector::AddMetricData, std::ref(collector), - CreateSumPointData()); - - first.join(); - second.join(); - - ASSERT_EQ(collector.GetCollection().size(), 2); -} - -/** - * Concurrency Test 2: After adding data concurrently and collecting, the intermediate collection - * should be empty, and all data are collected in the result vector. - */ -TEST(PrometheusCollector, ConcurrentlyAddingAndThenCollecting) -{ - PrometheusCollector collector; - - std::thread first(&PrometheusCollector::AddMetricData, std::ref(collector), CreateSumPointData()); - std::thread second(&PrometheusCollector::AddMetricData, std::ref(collector), - CreateSumPointData()); - first.join(); - second.join(); - - auto collect_future = std::async(&PrometheusCollector::Collect, std::ref(collector)); - auto res = collect_future.get(); - - ASSERT_EQ(collector.GetCollection().size(), 0); - ASSERT_EQ(res.size(), 2); -} - -/** - * Concurrency Test 3: Concurrently adding and collecting. We don't know when the collect function - * is called, but all data entries are either collected or left in the collection. - */ -TEST(PrometheusCollector, ConcurrentlyAddingAndCollecting) -{ - PrometheusCollector collector; - - // construct a collection to add metric records - - std::thread first(&PrometheusCollector::AddMetricData, std::ref(collector), CreateSumPointData()); - std::thread second(&PrometheusCollector::AddMetricData, std::ref(collector), - CreateSumPointData()); - auto collect_future = std::async(&PrometheusCollector::Collect, std::ref(collector)); - - first.join(); - second.join(); - - auto res = collect_future.get(); - - // the size of collection can be 0, 2, 4, because we don't know when the collect() - // is really called. However, we claim that if the data in the collection is collected, - // they must be in the res. So res.size() + collection.size() must be the total number - // of data records we generated. - ASSERT_EQ(res.size() + collector.GetCollection().size(), 2); -} - -/** - * Concurrency Test 4: Concurrently adding then concurrently collecting. We don't know which - * collecting thread fetches all data, but either one should succeed. - */ -TEST(PrometheusCollector, ConcurrentlyAddingAndConcurrentlyCollecting) -{ - PrometheusCollector collector; - - // concurrently adding - std::thread first(&PrometheusCollector::AddMetricData, std::ref(collector), CreateSumPointData()); - std::thread second(&PrometheusCollector::AddMetricData, std::ref(collector), - CreateSumPointData()); - first.join(); - second.join(); - - // after adding, then concurrently consuming - auto collect_future1 = std::async(&PrometheusCollector::Collect, std::ref(collector)); - auto collect_future2 = std::async(&PrometheusCollector::Collect, std::ref(collector)); - auto res1 = collect_future1.get(); - auto res2 = collect_future2.get(); - - // all added data must be collected in either res1 or res2 - ASSERT_EQ(res1.size() + res2.size(), 2); -} - -OPENTELEMETRY_END_NAMESPACE diff --git a/exporters/prometheus/test/exporter_test.cc b/exporters/prometheus/test/exporter_test.cc index c115dbfa87..3bda4c3d7b 100644 --- a/exporters/prometheus/test/exporter_test.cc +++ b/exporters/prometheus/test/exporter_test.cc @@ -5,6 +5,7 @@ #include "opentelemetry/exporters/prometheus/collector.h" #include "opentelemetry/exporters/prometheus/exporter.h" +#include "opentelemetry/sdk/metrics/instruments.h" #include "opentelemetry/version.h" #include "prometheus_test_helper.h" @@ -14,36 +15,24 @@ * an exposer as an argument, and instead takes no arguments; this * private constructor is only to be used here for testing */ -OPENTELEMETRY_BEGIN_NAMESPACE -namespace exporter -{ -namespace metrics -{ -class PrometheusExporterTest // : public ::testing::Test -{ -public: - PrometheusExporter GetExporter() { return PrometheusExporter(); } -}; -} // namespace metrics -} // namespace exporter -OPENTELEMETRY_END_NAMESPACE using opentelemetry::exporter::metrics::PrometheusCollector; using opentelemetry::exporter::metrics::PrometheusExporter; -using opentelemetry::exporter::metrics::PrometheusExporterTest; -using opentelemetry::sdk::common::ExportResult; - +using opentelemetry::exporter::metrics::PrometheusExporterOptions; +using opentelemetry::sdk::metrics::AggregationTemporality; +using opentelemetry::sdk::metrics::InstrumentType; /** * When a PrometheusExporter is initialized, * isShutdown should be false. */ TEST(PrometheusExporter, InitializeConstructorIsNotShutdown) { - PrometheusExporterTest p; - PrometheusExporter exporter = p.GetExporter(); - + PrometheusExporterOptions options; + options.url = "localhost:8081"; + PrometheusExporter exporter(options); // // Asserts that the exporter is not shutdown. - ASSERT_TRUE(!exporter.IsShutdown()); + // ASSERT_TRUE(!exporter.IsShutdown()); + exporter.Shutdown(); } /** @@ -51,8 +40,8 @@ TEST(PrometheusExporter, InitializeConstructorIsNotShutdown) */ TEST(PrometheusExporter, ShutdownSetsIsShutdownToTrue) { - PrometheusExporterTest p; - PrometheusExporter exporter = p.GetExporter(); + PrometheusExporterOptions options; + PrometheusExporter exporter(options); // exporter shuold not be shutdown by default ASSERT_TRUE(!exporter.IsShutdown()); @@ -68,93 +57,23 @@ TEST(PrometheusExporter, ShutdownSetsIsShutdownToTrue) } /** - * The Export() function should return kSuccess = 0 - * when data is exported successfully. - */ -TEST(PrometheusExporter, ExportSuccessfully) -{ - PrometheusExporterTest p; - PrometheusExporter exporter = p.GetExporter(); - - auto res = exporter.Export(CreateSumPointData()); - - // result should be kSuccess = 0 - ExportResult code = ExportResult::kSuccess; - ASSERT_EQ(res, code); -} - -/** - * If the exporter is shutdown, it cannot process - * any more export requests and returns kFailure = 1. - */ -TEST(PrometheusExporter, ExporterIsShutdown) -{ - PrometheusExporterTest p; - PrometheusExporter exporter = p.GetExporter(); - - exporter.Shutdown(); - - // send export request after shutdown - auto res = exporter.Export(CreateSumPointData()); - - // result code should be kFailure = 1 - ExportResult code = ExportResult::kFailure; - ASSERT_EQ(res, code); -} - -/** - * The Export() function should return - * kFailureFull = 2 when the collection is full, - * or when the collection is not full but does not have enough - * space to hold the batch data. - */ -TEST(PrometheusExporter, CollectionNotEnoughSpace) -{ - PrometheusExporterTest p; - PrometheusExporter exporter = p.GetExporter(); - - // prepare two collections of records to export, - // one close to max size and another one that, when added - // to the first, will exceed the size of the collection - - int max_collection_size = exporter.GetCollector()->GetMaxCollectionSize(); - - // send export request to fill the - // collection in the collector - ExportResult code = ExportResult::kSuccess; - for (int count = 1; count <= max_collection_size; ++count) - { - auto res = exporter.Export(CreateSumPointData()); - ASSERT_EQ(res, code); - } - - // send export request that does not complete - // due to not enough space in the collection - auto res = exporter.Export(CreateSumPointData()); - - // the result code should be kFailureFull = 2 - code = ExportResult::kFailureFull; - ASSERT_EQ(res, code); -} - -/** - * The Export() function should return - * kFailureInvalidArgument = 3 when an empty collection - * of records is passed to the Export() function. + * The Aggregation temporality should be correctly set */ -TEST(PrometheusExporter, InvalidArgumentWhenPassedEmptyRecordCollection) +TEST(PrometheusExporter, CheckAggregationTemporality) { - PrometheusExporterTest p; - PrometheusExporter exporter = p.GetExporter(); - - // Initializes an empty colelction of records - metric_sdk::ResourceMetrics data; - - // send export request to fill the - // collection in the collector - auto res = exporter.Export(data); - - // the result code should be kFailureInvalidArgument = 3 - ExportResult code = ExportResult::kFailureInvalidArgument; - ASSERT_EQ(res, code); + PrometheusExporterOptions options; + PrometheusExporter exporter(options); + + ASSERT_EQ(exporter.GetAggregationTemporality(InstrumentType::kCounter), + AggregationTemporality::kCumulative); + ASSERT_EQ(exporter.GetAggregationTemporality(InstrumentType::kHistogram), + AggregationTemporality::kCumulative); + ASSERT_EQ(exporter.GetAggregationTemporality(InstrumentType::kObservableCounter), + AggregationTemporality::kCumulative); + ASSERT_EQ(exporter.GetAggregationTemporality(InstrumentType::kObservableGauge), + AggregationTemporality::kCumulative); + ASSERT_EQ(exporter.GetAggregationTemporality(InstrumentType::kObservableUpDownCounter), + AggregationTemporality::kCumulative); + ASSERT_EQ(exporter.GetAggregationTemporality(InstrumentType::kUpDownCounter), + AggregationTemporality::kCumulative); } diff --git a/exporters/prometheus/test/exporter_utils_test.cc b/exporters/prometheus/test/exporter_utils_test.cc index 25e7ad0fdd..2b37ab77ad 100644 --- a/exporters/prometheus/test/exporter_utils_test.cc +++ b/exporters/prometheus/test/exporter_utils_test.cc @@ -48,11 +48,13 @@ void assert_basic(prometheus_client::MetricFamily &metric, } break; case prometheus_client::MetricType::Summary: - // Summary type not supported + // Summary and Info type not supported ASSERT_TRUE(false); break; case prometheus::MetricType::Untyped: break; + default: + break; } } @@ -63,12 +65,12 @@ void assert_histogram(prometheus_client::MetricFamily &metric, int cumulative_count = 0; auto buckets = metric.metric[0].histogram.bucket; auto boundary_it = boundaries.cbegin(); - for (size_t i = 0; i < buckets.size(); i++, ++boundary_it) + for (size_t i = 0; i < buckets.size(); i++) { auto bucket = buckets[i]; if (i != buckets.size() - 1) { - ASSERT_DOUBLE_EQ(*boundary_it, bucket.upper_bound); + ASSERT_DOUBLE_EQ(*boundary_it++, bucket.upper_bound); } else { @@ -81,67 +83,44 @@ void assert_histogram(prometheus_client::MetricFamily &metric, TEST(PrometheusExporterUtils, TranslateToPrometheusEmptyInputReturnsEmptyCollection) { - auto translated = PrometheusExporterUtils::TranslateToPrometheus( - std::vector>{}); + metric_sdk::ResourceMetrics metrics_data = {}; + auto translated = PrometheusExporterUtils::TranslateToPrometheus(metrics_data); ASSERT_EQ(translated.size(), 0); } TEST(PrometheusExporterUtils, TranslateToPrometheusIntegerCounter) { - std::vector> collection; - collection.emplace_back(new metric_sdk::ResourceMetrics{CreateSumPointData()}); + metric_sdk::ResourceMetrics metrics_data = CreateSumPointData(); - auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection); - ASSERT_EQ(translated.size(), collection.size()); + auto translated = PrometheusExporterUtils::TranslateToPrometheus(metrics_data); + ASSERT_EQ(translated.size(), 1); auto metric1 = translated[0]; std::vector vals = {10}; assert_basic(metric1, "library_name", "description", prometheus_client::MetricType::Counter, 1, vals); - - collection.emplace_back(new metric_sdk::ResourceMetrics{CreateSumPointData()}); - - translated = PrometheusExporterUtils::TranslateToPrometheus(collection); - ASSERT_EQ(translated.size(), collection.size()); - - auto metric2 = translated[1]; - assert_basic(metric2, "library_name", "description", prometheus_client::MetricType::Counter, 1, - vals); } TEST(PrometheusExporterUtils, TranslateToPrometheusIntegerLastValue) { - std::vector> collection; - - collection.emplace_back(new metric_sdk::ResourceMetrics{CreateLastValuePointData()}); + metric_sdk::ResourceMetrics metrics_data = CreateLastValuePointData(); - auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection); - ASSERT_EQ(translated.size(), collection.size()); + auto translated = PrometheusExporterUtils::TranslateToPrometheus(metrics_data); + ASSERT_EQ(translated.size(), 1); auto metric1 = translated[0]; std::vector vals = {10}; assert_basic(metric1, "library_name", "description", prometheus_client::MetricType::Gauge, 1, vals); - - collection.emplace_back(new metric_sdk::ResourceMetrics{CreateLastValuePointData()}); - - translated = PrometheusExporterUtils::TranslateToPrometheus(collection); - ASSERT_EQ(translated.size(), collection.size()); - - auto metric2 = translated[1]; - assert_basic(metric2, "library_name", "description", prometheus_client::MetricType::Gauge, 1, - vals); } TEST(PrometheusExporterUtils, TranslateToPrometheusHistogramNormal) { - std::vector> collection; - - collection.emplace_back(new metric_sdk::ResourceMetrics{CreateHistogramPointData()}); + metric_sdk::ResourceMetrics metrics_data = CreateHistogramPointData(); - auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection); - ASSERT_EQ(translated.size(), collection.size()); + auto translated = PrometheusExporterUtils::TranslateToPrometheus(metrics_data); + ASSERT_EQ(translated.size(), 1); auto metric = translated[0]; std::vector vals = {3, 900.5, 4}; diff --git a/exporters/zipkin/BUILD b/exporters/zipkin/BUILD index 5a23df1b24..16774e80df 100644 --- a/exporters/zipkin/BUILD +++ b/exporters/zipkin/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + package(default_visibility = ["//visibility:public"]) cc_library( diff --git a/exporters/zipkin/CMakeLists.txt b/exporters/zipkin/CMakeLists.txt index 0139a783e2..9cc997023f 100644 --- a/exporters/zipkin/CMakeLists.txt +++ b/exporters/zipkin/CMakeLists.txt @@ -1,42 +1,37 @@ -# Copyright 2021, 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. +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 include_directories(include) -find_package(CURL REQUIRED) add_definitions(-DWITH_CURL) add_library( opentelemetry_exporter_zipkin_trace src/zipkin_exporter.cc src/zipkin_exporter_factory.cc src/recordable.cc) +target_include_directories( + opentelemetry_exporter_zipkin_trace + PUBLIC "$" + "$") + target_link_libraries( opentelemetry_exporter_zipkin_trace PUBLIC opentelemetry_trace opentelemetry_http_client_curl nlohmann_json::nlohmann_json) -install( - TARGETS opentelemetry_exporter_zipkin_trace - EXPORT "${PROJECT_NAME}-target" - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +if(OPENTELEMETRY_INSTALL) + install( + TARGETS opentelemetry_exporter_zipkin_trace + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) -install( - DIRECTORY include/opentelemetry/exporters/zipkin - DESTINATION include/opentelemetry/exporters - FILES_MATCHING - PATTERN "*.h" - PATTERN "recordable.h" EXCLUDE) + install( + DIRECTORY include/opentelemetry/exporters/zipkin + DESTINATION include/opentelemetry/exporters + FILES_MATCHING + PATTERN "*.h" + PATTERN "recordable.h" EXCLUDE) +endif() if(BUILD_TESTING) add_definitions(-DGTEST_LINKED_AS_SHARED_LIBRARY=1) diff --git a/exporters/zipkin/include/opentelemetry/exporters/zipkin/zipkin_exporter.h b/exporters/zipkin/include/opentelemetry/exporters/zipkin/zipkin_exporter.h index cb2d7b6954..8c66a251a4 100644 --- a/exporters/zipkin/include/opentelemetry/exporters/zipkin/zipkin_exporter.h +++ b/exporters/zipkin/include/opentelemetry/exporters/zipkin/zipkin_exporter.h @@ -49,6 +49,14 @@ class ZipkinExporter final : public opentelemetry::sdk::trace::SpanExporter const nostd::span> &spans) noexcept override; + /** + * Force flush the exporter. + * @param timeout an option timeout, default to max. + * @return return true when all data are exported, and false when timeout + */ + bool ForceFlush( + std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override; + /** * Shut down the exporter. * @param timeout an optional timeout, default to max. diff --git a/exporters/zipkin/include/opentelemetry/exporters/zipkin/zipkin_exporter_options.h b/exporters/zipkin/include/opentelemetry/exporters/zipkin/zipkin_exporter_options.h index 299a5db4ed..f5ee941d22 100644 --- a/exporters/zipkin/include/opentelemetry/exporters/zipkin/zipkin_exporter_options.h +++ b/exporters/zipkin/include/opentelemetry/exporters/zipkin/zipkin_exporter_options.h @@ -18,9 +18,11 @@ inline const std::string GetDefaultZipkinEndpoint() const char *otel_exporter_zipkin_endpoint_env = "OTEL_EXPORTER_ZIPKIN_ENDPOINT"; const char *kZipkinEndpointDefault = "http://localhost:9411/api/v2/spans"; - auto endpoint = - opentelemetry::sdk::common::GetEnvironmentVariable(otel_exporter_zipkin_endpoint_env); - return endpoint.size() ? endpoint : kZipkinEndpointDefault; + std::string endpoint; + + auto exists = opentelemetry::sdk::common::GetStringEnvironmentVariable( + otel_exporter_zipkin_endpoint_env, endpoint); + return exists ? endpoint : kZipkinEndpointDefault; } enum class TransportFormat diff --git a/exporters/zipkin/src/zipkin_exporter.cc b/exporters/zipkin/src/zipkin_exporter.cc index 802ecccffc..2dd8a3e884 100644 --- a/exporters/zipkin/src/zipkin_exporter.cc +++ b/exporters/zipkin/src/zipkin_exporter.cc @@ -76,7 +76,7 @@ sdk::common::ExportResult ZipkinExporter::Export( } auto body_s = json_spans.dump(); http_client::Body body_v(body_s.begin(), body_s.end()); - auto result = http_client_->Post(url_parser_.url_, body_v, options_.headers); + auto result = http_client_->PostNoSsl(url_parser_.url_, body_v, options_.headers); if (result && (result.GetResponse().GetStatusCode() == 200 || result.GetResponse().GetStatusCode() == 202)) { @@ -110,6 +110,11 @@ void ZipkinExporter::InitializeLocalEndpoint() local_end_point_["port"] = url_parser_.port_; } +bool ZipkinExporter::ForceFlush(std::chrono::microseconds /* timeout */) noexcept +{ + return true; +} + bool ZipkinExporter::Shutdown(std::chrono::microseconds /* timeout */) noexcept { const std::lock_guard locked(lock_); diff --git a/exporters/zipkin/test/zipkin_exporter_test.cc b/exporters/zipkin/test/zipkin_exporter_test.cc index af518d1655..f8493bec6d 100644 --- a/exporters/zipkin/test/zipkin_exporter_test.cc +++ b/exporters/zipkin/test/zipkin_exporter_test.cc @@ -58,16 +58,36 @@ class ZipkinExporterTestPeer : public ::testing::Test class MockHttpClient : public opentelemetry::ext::http::client::HttpClientSync { public: +# ifdef ENABLE_HTTP_SSL_PREVIEW MOCK_METHOD(ext::http::client::Result, Post, (const nostd::string_view &, + const ext::http::client::HttpSslOptions &, const ext::http::client::Body &, const ext::http::client::Headers &), (noexcept, override)); +# else + MOCK_METHOD(ext::http::client::Result, + Post, + (const nostd::string_view &, + const ext::http::client::Body &, + const ext::http::client::Headers &), + (noexcept, override)); +# endif /* ENABLE_HTTP_SSL_PREVIEW */ + +# ifdef ENABLE_HTTP_SSL_PREVIEW + MOCK_METHOD(ext::http::client::Result, + Get, + (const nostd::string_view &, + const ext::http::client::HttpSslOptions &, + const ext::http::client::Headers &), + (noexcept, override)); +# else MOCK_METHOD(ext::http::client::Result, Get, (const nostd::string_view &, const ext::http::client::Headers &), (noexcept, override)); +# endif /* ENABLE_HTTP_SSL_PREVIEW */ }; class IsValidMessageMatcher @@ -146,7 +166,13 @@ TEST_F(ZipkinExporterTestPeer, ExportJsonIntegrationTest) report_trace_id.assign(trace_id_hex, sizeof(trace_id_hex)); auto expected_url = nostd::string_view{"http://localhost:9411/api/v2/spans"}; + +# ifdef ENABLE_HTTP_SSL_PREVIEW + EXPECT_CALL(*mock_http_client, Post(expected_url, _, IsValidMessage(report_trace_id), _)) +# else EXPECT_CALL(*mock_http_client, Post(expected_url, IsValidMessage(report_trace_id), _)) +# endif /* ENABLE_HTTP_SSL_PREVIEW */ + .Times(Exactly(1)) .WillOnce(Return(ByMove(ext::http::client::Result{ std::unique_ptr{new ext::http::client::curl::Response()}, @@ -168,9 +194,15 @@ TEST_F(ZipkinExporterTestPeer, ShutdownTest) auto recordable_2 = exporter->MakeRecordable(); recordable_2->SetName("Test span 2"); - // exporter shuold not be shutdown by default + // exporter should not be shutdown by default nostd::span> batch_1(&recordable_1, 1); + +# ifdef ENABLE_HTTP_SSL_PREVIEW + EXPECT_CALL(*mock_http_client, Post(_, _, _, _)) +# else EXPECT_CALL(*mock_http_client, Post(_, _, _)) +# endif /* ENABLE_HTTP_SSL_PREVIEW */ + .Times(Exactly(1)) .WillOnce(Return(ByMove(ext::http::client::Result{ std::unique_ptr{new ext::http::client::curl::Response()}, diff --git a/ext/BUILD b/ext/BUILD index cc62431b53..b19ae921e5 100644 --- a/ext/BUILD +++ b/ext/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + package(default_visibility = ["//visibility:public"]) cc_library( diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt index 034328eaa5..bae59e3040 100644 --- a/ext/CMakeLists.txt +++ b/ext/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + add_library(opentelemetry_ext INTERFACE) target_include_directories( opentelemetry_ext @@ -7,18 +10,20 @@ target_include_directories( set_target_properties(opentelemetry_ext PROPERTIES EXPORT_NAME "ext") target_link_libraries(opentelemetry_ext INTERFACE opentelemetry_api) -install( - TARGETS opentelemetry_ext - EXPORT "${PROJECT_NAME}-target" - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +if(OPENTELEMETRY_INSTALL) + install( + TARGETS opentelemetry_ext + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) -install( - DIRECTORY include/opentelemetry/ext - DESTINATION include/opentelemetry/ - FILES_MATCHING - PATTERN "*.h") + install( + DIRECTORY include/opentelemetry/ext + DESTINATION include/opentelemetry/ + FILES_MATCHING + PATTERN "*.h") +endif() add_subdirectory(src) diff --git a/ext/include/opentelemetry/ext/http/client/curl/http_client_curl.h b/ext/include/opentelemetry/ext/http/client/curl/http_client_curl.h index 43992bbdf5..dfce580d9d 100644 --- a/ext/include/opentelemetry/ext/http/client/curl/http_client_curl.h +++ b/ext/include/opentelemetry/ext/http/client/curl/http_client_curl.h @@ -57,6 +57,13 @@ class Request : public opentelemetry::ext::http::client::Request method_ = method; } +#ifdef ENABLE_HTTP_SSL_PREVIEW + void SetSslOptions(const HttpSslOptions &ssl_options) noexcept override + { + ssl_options_ = ssl_options; + } +#endif /* ENABLE_HTTP_SSL_PREVIEW */ + void SetBody(opentelemetry::ext::http::client::Body &body) noexcept override { body_ = std::move(body); @@ -85,6 +92,11 @@ class Request : public opentelemetry::ext::http::client::Request public: opentelemetry::ext::http::client::Method method_; + +#ifdef ENABLE_HTTP_SSL_PREVIEW + opentelemetry::ext::http::client::HttpSslOptions ssl_options_; +#endif /* ENABLE_HTTP_SSL_PREVIEW */ + opentelemetry::ext::http::client::Body body_; opentelemetry::ext::http::client::Headers headers_; std::string uri_; @@ -214,11 +226,19 @@ class HttpClientSync : public opentelemetry::ext::http::client::HttpClientSync opentelemetry::ext::http::client::Result Get( const nostd::string_view &url, +#ifdef ENABLE_HTTP_SSL_PREVIEW + const opentelemetry::ext::http::client::HttpSslOptions &ssl_options, +#endif /* ENABLE_HTTP_SSL_PREVIEW */ const opentelemetry::ext::http::client::Headers &headers) noexcept override { opentelemetry::ext::http::client::Body body; - HttpOperation curl_operation(opentelemetry::ext::http::client::Method::Get, url.data(), nullptr, - headers, body); + + HttpOperation curl_operation(opentelemetry::ext::http::client::Method::Get, url.data(), +#ifdef ENABLE_HTTP_SSL_PREVIEW + ssl_options, +#endif /* ENABLE_HTTP_SSL_PREVIEW */ + nullptr, headers, body); + curl_operation.SendSync(); auto session_state = curl_operation.GetSessionState(); if (curl_operation.WasAborted()) @@ -239,10 +259,16 @@ class HttpClientSync : public opentelemetry::ext::http::client::HttpClientSync opentelemetry::ext::http::client::Result Post( const nostd::string_view &url, +#ifdef ENABLE_HTTP_SSL_PREVIEW + const opentelemetry::ext::http::client::HttpSslOptions &ssl_options, +#endif /* ENABLE_HTTP_SSL_PREVIEW */ const Body &body, const opentelemetry::ext::http::client::Headers &headers) noexcept override { HttpOperation curl_operation(opentelemetry::ext::http::client::Method::Post, url.data(), +#ifdef ENABLE_HTTP_SSL_PREVIEW + ssl_options, +#endif /* ENABLE_HTTP_SSL_PREVIEW */ nullptr, headers, body); curl_operation.SendSync(); auto session_state = curl_operation.GetSessionState(); @@ -263,6 +289,7 @@ class HttpClientSync : public opentelemetry::ext::http::client::HttpClientSync return opentelemetry::ext::http::client::Result(std::move(response), session_state); } +public: ~HttpClientSync() override {} private: diff --git a/ext/include/opentelemetry/ext/http/client/curl/http_operation_curl.h b/ext/include/opentelemetry/ext/http/client/curl/http_operation_curl.h index d1c6e16d96..55a488f131 100644 --- a/ext/include/opentelemetry/ext/http/client/curl/http_operation_curl.h +++ b/ext/include/opentelemetry/ext/http/client/curl/http_operation_curl.h @@ -6,7 +6,13 @@ #include "opentelemetry/ext/http/client/http_client.h" #include "opentelemetry/version.h" -#include +#if defined(_MSC_VER) +# pragma warning(suppress : 5204) +# include +#else +# include +#endif + #include #include #include @@ -132,6 +138,9 @@ class HttpOperation */ HttpOperation(opentelemetry::ext::http::client::Method method, std::string url, +#ifdef ENABLE_HTTP_SSL_PREVIEW + const opentelemetry::ext::http::client::HttpSslOptions &ssl_options, +#endif /* ENABLE_HTTP_SSL_PREVIEW */ opentelemetry::ext::http::client::EventHandler *event_handle, // Default empty headers and empty request body const opentelemetry::ext::http::client::Headers &request_headers = @@ -239,6 +248,28 @@ class HttpOperation inline CURL *GetCurlEasyHandle() noexcept { return curl_resource_.easy_handle; } private: + CURLcode SetCurlPtrOption(CURLoption option, void *value); + + CURLcode SetCurlStrOption(CURLoption option, const char *str) + { + void *ptr = const_cast(str); + return SetCurlPtrOption(option, ptr); + } + + CURLcode SetCurlBlobOption(CURLoption option, struct curl_blob *blob) + { + return SetCurlPtrOption(option, blob); + } + + CURLcode SetCurlListOption(CURLoption option, struct curl_slist *list) + { + return SetCurlPtrOption(option, list); + } + + CURLcode SetCurlLongOption(CURLoption option, long value); + + const char *GetCurlErrorMessage(CURLcode code); + std::atomic is_aborted_; // Set to 'true' when async callback is aborted std::atomic is_finished_; // Set to 'true' when async callback is finished. std::atomic is_cleaned_; // Set to 'true' when async callback is cleaned. @@ -246,6 +277,7 @@ class HttpOperation const bool reuse_connection_; // Reuse connection const std::chrono::milliseconds http_conn_timeout_; // Timeout for connect. Default: 5000ms + char curl_error_message_[CURL_ERROR_SIZE]; HttpCurlEasyResource curl_resource_; CURLcode last_curl_result_; // Curl result OR HTTP status code if successful @@ -254,6 +286,11 @@ class HttpOperation // Request values opentelemetry::ext::http::client::Method method_; std::string url_; + +#ifdef ENABLE_HTTP_SSL_PREVIEW + const opentelemetry::ext::http::client::HttpSslOptions &ssl_options_; +#endif /* ENABLE_HTTP_SSL_PREVIEW */ + const Headers &request_headers_; const opentelemetry::ext::http::client::Body &request_body_; size_t request_nwrite_; diff --git a/ext/include/opentelemetry/ext/http/client/http_client.h b/ext/include/opentelemetry/ext/http/client/http_client.h index 0f34533265..c3559cb0eb 100644 --- a/ext/include/opentelemetry/ext/http/client/http_client.h +++ b/ext/include/opentelemetry/ext/http/client/http_client.h @@ -4,6 +4,7 @@ #pragma once #include +#include #include #include #include @@ -94,10 +95,9 @@ enum class SessionState Cancelled // (manually) cancelled }; -using Byte = uint8_t; -using StatusCode = uint16_t; -using Body = std::vector; -using SSLCertificate = std::vector; +using Byte = uint8_t; +using StatusCode = uint16_t; +using Body = std::vector; struct cmp_ic { @@ -110,6 +110,130 @@ struct cmp_ic }; using Headers = std::multimap; +#ifdef ENABLE_HTTP_SSL_PREVIEW +struct HttpSslOptions +{ + HttpSslOptions() {} + + HttpSslOptions(nostd::string_view url, + bool input_ssl_insecure_skip_verify, + nostd::string_view input_ssl_ca_cert_path, + nostd::string_view input_ssl_ca_cert_string, + nostd::string_view input_ssl_client_key_path, + nostd::string_view input_ssl_client_key_string, + nostd::string_view input_ssl_client_cert_path, + nostd::string_view input_ssl_client_cert_string +# ifdef ENABLE_HTTP_SSL_TLS_PREVIEW + , + nostd::string_view input_ssl_min_tls, + nostd::string_view input_ssl_max_tls, + nostd::string_view input_ssl_cipher, + nostd::string_view input_ssl_cipher_suite +# endif /* ENABLE_HTTP_SSL_TLS_PREVIEW */ + ) + : use_ssl(false), + ssl_insecure_skip_verify(input_ssl_insecure_skip_verify), + ssl_ca_cert_path(input_ssl_ca_cert_path), + ssl_ca_cert_string(input_ssl_ca_cert_string), + ssl_client_key_path(input_ssl_client_key_path), + ssl_client_key_string(input_ssl_client_key_string), + ssl_client_cert_path(input_ssl_client_cert_path), + ssl_client_cert_string(input_ssl_client_cert_string) + +# ifdef ENABLE_HTTP_SSL_TLS_PREVIEW + , + ssl_min_tls(input_ssl_min_tls), + ssl_max_tls(input_ssl_max_tls), + ssl_cipher(input_ssl_cipher), + ssl_cipher_suite(input_ssl_cipher_suite) +# endif /* ENABLE_HTTP_SSL_TLS_PREVIEW */ + { + /* Use SSL if url starts with "https:" */ + if (strncmp(url.data(), "https:", 6) == 0) + { + use_ssl = true; + } + } + + /** + Use HTTPS (true) or HTTP (false). + */ + bool use_ssl{false}; + /** + Skip SSL/TLS verifications. + Setting this flag to true is insecure. + */ + bool ssl_insecure_skip_verify{false}; + /** + Path to the CA CERT file. + */ + std::string ssl_ca_cert_path{}; + /** + CA CERT. + Used only if @p ssl_ca_cert_path is empty. + */ + std::string ssl_ca_cert_string{}; + /** + Path to the client key file. + */ + std::string ssl_client_key_path{}; + /** + Client key. + Used only if @p ssl_client_key_path is empty. + */ + std::string ssl_client_key_string{}; + /** + Path to the client cert file. + */ + std::string ssl_client_cert_path{}; + /** + Client cert. + Used only if @p ssl_client_cert_path is empty. + */ + std::string ssl_client_cert_string{}; + +# ifdef ENABLE_HTTP_SSL_TLS_PREVIEW + /** + Minimum SSL version to use. + Valid values are: + - empty (no minimum version required) + - "1.0" (TLSv1.0) + - "1.1" (TLSv1.1) + - "1.2" (TLSv1.2) + - "1.3" (TLSv1.3) + */ + std::string ssl_min_tls{}; + + /** + Maximum SSL version to use. + Valid values are: + - empty (no maximum version required) + - "1.0" (TLSv1.0) + - "1.1" (TLSv1.1) + - "1.2" (TLSv1.2) + - "1.3" (TLSv1.3) + */ + std::string ssl_max_tls{}; + + /** + TLS Cipher. + This is for TLS 1.0, 1.1 and 1.2. + The list is delimited by colons (":"). + Cipher names depends on the underlying CURL implementation. + */ + std::string ssl_cipher{}; + + /** + TLS Cipher suite. + This is for TLS 1.3. + The list is delimited by colons (":"). + Cipher names depends on the underlying CURL implementation. + */ + std::string ssl_cipher_suite{}; +# endif /* ENABLE_HTTP_SSL_TLS_PREVIEW */ +}; +#endif /* ENABLE_HTTP_SSL_PREVIEW */ + class Request { public: @@ -117,6 +241,10 @@ class Request virtual void SetUri(nostd::string_view uri) noexcept = 0; +#ifdef ENABLE_HTTP_SSL_PREVIEW + virtual void SetSslOptions(const HttpSslOptions &options) noexcept = 0; +#endif /* ENABLE_HTTP_SSL_PREVIEW */ + virtual void SetBody(Body &body) noexcept = 0; virtual void AddHeader(nostd::string_view name, nostd::string_view value) noexcept = 0; @@ -202,8 +330,6 @@ class EventHandler virtual void OnEvent(SessionState, nostd::string_view) noexcept = 0; - virtual void OnConnecting(const SSLCertificate &) noexcept {} - virtual ~EventHandler() = default; }; @@ -240,9 +366,38 @@ class HttpClient class HttpClientSync { public: - virtual Result Get(const nostd::string_view &url, const Headers & = {{}}) noexcept = 0; + Result GetNoSsl(const nostd::string_view &url, const Headers &headers = {{}}) noexcept + { +#ifdef ENABLE_HTTP_SSL_PREVIEW + static const HttpSslOptions no_ssl; + return Get(url, no_ssl, headers); +#else + return Get(url, headers); +#endif /* ENABLE_HTTP_SSL_PREVIEW */ + } + + virtual Result PostNoSsl(const nostd::string_view &url, + const Body &body, + const Headers &headers = {{"content-type", "application/json"}}) noexcept + { +#ifdef ENABLE_HTTP_SSL_PREVIEW + static const HttpSslOptions no_ssl; + return Post(url, no_ssl, body, headers); +#else + return Post(url, body, headers); +#endif /* ENABLE_HTTP_SSL_PREVIEW */ + } + + virtual Result Get(const nostd::string_view &url, +#ifdef ENABLE_HTTP_SSL_PREVIEW + const HttpSslOptions &ssl_options, +#endif /* ENABLE_HTTP_SSL_PREVIEW */ + const Headers & = {{}}) noexcept = 0; virtual Result Post(const nostd::string_view &url, +#ifdef ENABLE_HTTP_SSL_PREVIEW + const HttpSslOptions &ssl_options, +#endif /* ENABLE_HTTP_SSL_PREVIEW */ const Body &body, const Headers & = {{"content-type", "application/json"}}) noexcept = 0; diff --git a/ext/src/CMakeLists.txt b/ext/src/CMakeLists.txt index 6d7a14be41..bc1f614eb9 100644 --- a/ext/src/CMakeLists.txt +++ b/ext/src/CMakeLists.txt @@ -1,5 +1,14 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + if(WITH_ZPAGES) add_subdirectory(zpages) endif() -add_subdirectory(http/client/curl) +if(WITH_HTTP_CLIENT_CURL) + add_subdirectory(http/client/curl) +endif() + +if(MSVC AND DEFINED OPENTELEMETRY_BUILD_DLL) + add_subdirectory(dll) +endif() diff --git a/ext/src/dll/CMakeLists.txt b/ext/src/dll/CMakeLists.txt new file mode 100644 index 0000000000..4cfcd87412 --- /dev/null +++ b/ext/src/dll/CMakeLists.txt @@ -0,0 +1,55 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +set(OPENTELEMETRY_EXPORT_DEF + "${CMAKE_CURRENT_BINARY_DIR}/opentelemetry_cpp.def") + +add_library(opentelemetry_cpp SHARED dllmain.cc ${OPENTELEMETRY_EXPORT_DEF}) + +target_link_libraries( + opentelemetry_cpp PRIVATE opentelemetry_trace + opentelemetry_exporter_ostream_span) + +if(WITH_OTLP_GRPC) + add_compile_definitions(WITH_OTLP_GRPC) + target_link_libraries(opentelemetry_cpp + PRIVATE opentelemetry_exporter_otlp_grpc) +endif() + +if(WITH_OTLP_HTTP) + add_compile_definitions(WITH_OTLP_HTTP) + target_link_libraries(opentelemetry_cpp + PRIVATE opentelemetry_exporter_otlp_http) +endif() + +if(WITH_LOGS_PREVIEW) + if(WITH_OTLP_GRPC) + target_link_libraries( + opentelemetry_cpp PRIVATE opentelemetry_logs + opentelemetry_exporter_otlp_grpc_log) + endif() + + if(WITH_OTLP_HTTP) + target_link_libraries( + opentelemetry_cpp PRIVATE opentelemetry_logs + opentelemetry_exporter_otlp_http_log) + endif() +endif() + +add_custom_command( + OUTPUT ${OPENTELEMETRY_EXPORT_DEF} + COMMAND + ${CMAKE_CXX_COMPILER} + "-D$,;-D>" /EP + ${CMAKE_CURRENT_SOURCE_DIR}/opentelemetry_cpp.src > + ${OPENTELEMETRY_EXPORT_DEF} + COMMAND_EXPAND_LISTS VERBATIM) + +if(OPENTELEMETRY_INSTALL) + install( + TARGETS opentelemetry_cpp + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif() diff --git a/ext/src/dll/dllmain.cc b/ext/src/dll/dllmain.cc new file mode 100644 index 0000000000..3dc5bc5c11 --- /dev/null +++ b/ext/src/dll/dllmain.cc @@ -0,0 +1,20 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include + +// Include API header files here for exporting +#include + +#if defined(ENABLE_LOGS_PREVIEW) +# include +#endif // ENABLE_LOGS_PREVIEW + +extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) +{ + UNREFERENCED_PARAMETER(hInstance); + UNREFERENCED_PARAMETER(dwReason); + UNREFERENCED_PARAMETER(lpReserved); + + return TRUE; +} diff --git a/ext/src/dll/opentelemetry_cpp.src b/ext/src/dll/opentelemetry_cpp.src new file mode 100644 index 0000000000..9f5ee76ba3 --- /dev/null +++ b/ext/src/dll/opentelemetry_cpp.src @@ -0,0 +1,39 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// clang-format off +LIBRARY opentelemetry_cpp +EXPORTS + // public: static class std::unique_ptr > __cdecl opentelemetry::v1::exporter::trace::OStreamSpanExporterFactory::Create(void) + ?Create@OStreamSpanExporterFactory@trace@exporter@v1@opentelemetry@@SA?AV?$unique_ptr@VSpanExporter@trace@sdk@v1@opentelemetry@@U?$default_delete@VSpanExporter@trace@sdk@v1@opentelemetry@@@std@@@std@@XZ + // public: static class std::unique_ptr > __cdecl opentelemetry::v1::sdk::trace::SimpleSpanProcessorFactory::Create(class std::unique_ptr > && __ptr64) + ?Create@SimpleSpanProcessorFactory@trace@sdk@v1@opentelemetry@@SA?AV?$unique_ptr@VSpanProcessor@trace@sdk@v1@opentelemetry@@U?$default_delete@VSpanProcessor@trace@sdk@v1@opentelemetry@@@std@@@std@@$$QEAV?$unique_ptr@VSpanExporter@trace@sdk@v1@opentelemetry@@U?$default_delete@VSpanExporter@trace@sdk@v1@opentelemetry@@@std@@@7@@Z + // public: static class std::unique_ptr > __cdecl opentelemetry::v1::sdk::trace::TracerProviderFactory::Create(class std::unique_ptr >) + ?Create@TracerProviderFactory@trace@sdk@v1@opentelemetry@@SA?AV?$unique_ptr@VTracerProvider@trace@v1@opentelemetry@@U?$default_delete@VTracerProvider@trace@v1@opentelemetry@@@std@@@std@@V?$unique_ptr@VSpanProcessor@trace@sdk@v1@opentelemetry@@U?$default_delete@VSpanProcessor@trace@sdk@v1@opentelemetry@@@std@@@7@@Z +#if defined(WITH_OTLP_GRPC) + // public: static class std::unique_ptr > __cdecl opentelemetry::v1::exporter::otlp::OtlpGrpcExporterFactory::Create(struct opentelemetry::v1::exporter::otlp::OtlpGrpcExporterOptions const & __ptr64) + ?Create@OtlpGrpcExporterFactory@otlp@exporter@v1@opentelemetry@@SA?AV?$unique_ptr@VSpanExporter@trace@sdk@v1@opentelemetry@@U?$default_delete@VSpanExporter@trace@sdk@v1@opentelemetry@@@std@@@std@@AEBUOtlpGrpcExporterOptions@2345@@Z +#endif // defined(WITH_OTLP_GRPC) +#if defined(WITH_OTLP_HTTP) + // public: static class std::unique_ptr > __cdecl opentelemetry::v1::exporter::otlp::OtlpHttpExporterFactory::Create(struct opentelemetry::v1::exporter::otlp::OtlpHttpExporterOptions const & __ptr64) + ?Create@OtlpHttpExporterFactory@otlp@exporter@v1@opentelemetry@@SA?AV?$unique_ptr@VSpanExporter@trace@sdk@v1@opentelemetry@@U?$default_delete@VSpanExporter@trace@sdk@v1@opentelemetry@@@std@@@std@@AEBUOtlpHttpExporterOptions@2345@@Z +#endif // defined(WITH_OTLP_HTTP) +#if defined(ENABLE_LOGS_PREVIEW) + // public: static class std::unique_ptr > __cdecl opentelemetry::v1::sdk::logs::LoggerProviderFactory::Create(class std::unique_ptr > && __ptr64) + ?Create@LoggerProviderFactory@logs@sdk@v1@opentelemetry@@SA?AV?$unique_ptr@VLoggerProvider@logs@v1@opentelemetry@@U?$default_delete@VLoggerProvider@logs@v1@opentelemetry@@@std@@@std@@$$QEAV?$unique_ptr@VLogRecordProcessor@logs@sdk@v1@opentelemetry@@U?$default_delete@VLogRecordProcessor@logs@sdk@v1@opentelemetry@@@std@@@7@@Z + // public: static class std::unique_ptr > __cdecl opentelemetry::v1::sdk::logs::BatchLogRecordProcessorFactory::Create(class std::unique_ptr > && __ptr64,struct opentelemetry::v1::sdk::logs::BatchLogRecordProcessorOptions const & __ptr64) + ?Create@BatchLogRecordProcessorFactory@logs@sdk@v1@opentelemetry@@SA?AV?$unique_ptr@VLogRecordProcessor@logs@sdk@v1@opentelemetry@@U?$default_delete@VLogRecordProcessor@logs@sdk@v1@opentelemetry@@@std@@@std@@$$QEAV?$unique_ptr@VLogRecordExporter@logs@sdk@v1@opentelemetry@@U?$default_delete@VLogRecordExporter@logs@sdk@v1@opentelemetry@@@std@@@7@AEBUBatchLogRecordProcessorOptions@2345@@Z + // public: static class std::unique_ptr > __cdecl opentelemetry::v1::sdk::logs::SimpleLogRecordProcessorFactory::Create(class std::unique_ptr > && __ptr64) + ?Create@SimpleLogRecordProcessorFactory@logs@sdk@v1@opentelemetry@@SA?AV?$unique_ptr@VLogRecordProcessor@logs@sdk@v1@opentelemetry@@U?$default_delete@VLogRecordProcessor@logs@sdk@v1@opentelemetry@@@std@@@std@@$$QEAV?$unique_ptr@VLogRecordExporter@logs@sdk@v1@opentelemetry@@U?$default_delete@VLogRecordExporter@logs@sdk@v1@opentelemetry@@@std@@@7@@Z + // public: static class std::unique_ptr > __cdecl opentelemetry::v1::sdk::logs::MultiLogRecordProcessorFactory::Create(class std::vector >,class std::allocator > > > && __ptr64) + ?Create@MultiLogRecordProcessorFactory@logs@sdk@v1@opentelemetry@@SA?AV?$unique_ptr@VLogRecordProcessor@logs@sdk@v1@opentelemetry@@U?$default_delete@VLogRecordProcessor@logs@sdk@v1@opentelemetry@@@std@@@std@@$$QEAV?$vector@V?$unique_ptr@VLogRecordProcessor@logs@sdk@v1@opentelemetry@@U?$default_delete@VLogRecordProcessor@logs@sdk@v1@opentelemetry@@@std@@@std@@V?$allocator@V?$unique_ptr@VLogRecordProcessor@logs@sdk@v1@opentelemetry@@U?$default_delete@VLogRecordProcessor@logs@sdk@v1@opentelemetry@@@std@@@std@@@2@@7@@Z +#if defined(WITH_OTLP_GRPC) + // public: static class std::unique_ptr > __cdecl opentelemetry::v1::exporter::otlp::OtlpGrpcLogRecordExporterFactory::Create(struct opentelemetry::v1::exporter::otlp::OtlpGrpcExporterOptions const & __ptr64) + ?Create@OtlpGrpcLogRecordExporterFactory@otlp@exporter@v1@opentelemetry@@SA?AV?$unique_ptr@VLogRecordExporter@logs@sdk@v1@opentelemetry@@U?$default_delete@VLogRecordExporter@logs@sdk@v1@opentelemetry@@@std@@@std@@AEBUOtlpGrpcExporterOptions@2345@@Z +#endif // defined(WITH_OTLP_GRPC) +#if defined(WITH_OTLP_HTTP) + // public: static class std::unique_ptr > __cdecl opentelemetry::v1::exporter::otlp::OtlpHttpLogRecordExporterFactory::Create(struct opentelemetry::v1::exporter::otlp::OtlpHttpLogRecordExporterOptions const & __ptr64) + ?Create@OtlpHttpLogRecordExporterFactory@otlp@exporter@v1@opentelemetry@@SA?AV?$unique_ptr@VLogRecordExporter@logs@sdk@v1@opentelemetry@@U?$default_delete@VLogRecordExporter@logs@sdk@v1@opentelemetry@@@std@@@std@@AEBUOtlpHttpLogRecordExporterOptions@2345@@Z +#endif // defined(WITH_OTLP_HTTP) +#endif // defined(ENABLE_LOGS_PREVIEW) +// clang-format on diff --git a/ext/src/http/client/curl/BUILD b/ext/src/http/client/curl/BUILD index c0557fe99c..8c2dda1ebe 100644 --- a/ext/src/http/client/curl/BUILD +++ b/ext/src/http/client/curl/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + package(default_visibility = ["//visibility:public"]) cc_library( diff --git a/ext/src/http/client/curl/CMakeLists.txt b/ext/src/http/client/curl/CMakeLists.txt index 836cd019b4..6684c5f820 100644 --- a/ext/src/http/client/curl/CMakeLists.txt +++ b/ext/src/http/client/curl/CMakeLists.txt @@ -1,26 +1,28 @@ -find_package(CURL) -if(CURL_FOUND) - add_library( - opentelemetry_http_client_curl http_client_factory_curl.cc - http_client_curl.cc http_operation_curl.cc) +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 - set_target_properties(opentelemetry_http_client_curl - PROPERTIES EXPORT_NAME http_client_curl) +add_library( + opentelemetry_http_client_curl http_client_factory_curl.cc + http_client_curl.cc http_operation_curl.cc) - if(TARGET CURL::libcurl) - target_link_libraries( - opentelemetry_http_client_curl - PUBLIC opentelemetry_ext - PRIVATE CURL::libcurl) - else() - target_include_directories(opentelemetry_http_client_curl - INTERFACE "${CURL_INCLUDE_DIRS}") - target_link_libraries( - opentelemetry_http_client_curl - PUBLIC opentelemetry_ext - PRIVATE ${CURL_LIBRARIES}) - endif() +set_target_properties(opentelemetry_http_client_curl + PROPERTIES EXPORT_NAME http_client_curl) +if(TARGET CURL::libcurl) + target_link_libraries( + opentelemetry_http_client_curl + PUBLIC opentelemetry_ext + PRIVATE CURL::libcurl) +else() + target_include_directories(opentelemetry_http_client_curl + INTERFACE "${CURL_INCLUDE_DIRS}") + target_link_libraries( + opentelemetry_http_client_curl + PUBLIC opentelemetry_ext + PRIVATE ${CURL_LIBRARIES}) +endif() + +if(OPENTELEMETRY_INSTALL) install( TARGETS opentelemetry_http_client_curl EXPORT "${PROJECT_NAME}-target" diff --git a/ext/src/http/client/curl/http_client_curl.cc b/ext/src/http/client/curl/http_client_curl.cc index 3ba0133633..52942f6433 100644 --- a/ext/src/http/client/curl/http_client_curl.cc +++ b/ext/src/http/client/curl/http_client_curl.cc @@ -48,9 +48,13 @@ void Session::SendRequest( reuse_connection = session_id_ % http_client_.GetMaxSessionsPerConnection() != 0; } - curl_operation_.reset(new HttpOperation(http_request_->method_, url, callback_ptr, - http_request_->headers_, http_request_->body_, false, - http_request_->timeout_ms_, reuse_connection)); + curl_operation_.reset(new HttpOperation(http_request_->method_, url, +#ifdef ENABLE_HTTP_SSL_PREVIEW + http_request_->ssl_options_, +#endif /* ENABLE_HTTP_SSL_PREVIEW */ + callback_ptr, http_request_->headers_, + http_request_->body_, false, http_request_->timeout_ms_, + reuse_connection)); bool success = CURLE_OK == curl_operation_->SendAsync(this, [this, callback](HttpOperation &operation) { if (operation.WasAborted()) @@ -253,7 +257,9 @@ void HttpClient::CleanupSession(uint64_t session_id) } else if (session->IsSessionActive() && session->GetOperation()) { - session->FinishOperation(); + // If this session is alread waiting to be removed, just wakeup background thread to call + // doRemoveSessions() + wakeupBackgroundThread(); } } } diff --git a/ext/src/http/client/curl/http_operation_curl.cc b/ext/src/http/client/curl/http_operation_curl.cc index ec1c872489..4d472ac7f5 100644 --- a/ext/src/http/client/curl/http_operation_curl.cc +++ b/ext/src/http/client/curl/http_operation_curl.cc @@ -6,6 +6,7 @@ #include "opentelemetry/ext/http/client/curl/http_operation_curl.h" #include "opentelemetry/ext/http/client/curl/http_client_curl.h" +#include "opentelemetry/sdk/common/global_log_handler.h" OPENTELEMETRY_BEGIN_NAMESPACE namespace ext @@ -229,6 +230,9 @@ void HttpOperation::DispatchEvent(opentelemetry::ext::http::client::SessionState HttpOperation::HttpOperation(opentelemetry::ext::http::client::Method method, std::string url, +#ifdef ENABLE_HTTP_SSL_PREVIEW + const HttpSslOptions &ssl_options, +#endif /* ENABLE_HTTP_SSL_PREVIEW */ opentelemetry::ext::http::client::EventHandler *event_handle, // Default empty headers and empty request body const opentelemetry::ext::http::client::Headers &request_headers, @@ -249,6 +253,9 @@ HttpOperation::HttpOperation(opentelemetry::ext::http::client::Method method, event_handle_(event_handle), method_(method), url_(url), +#ifdef ENABLE_HTTP_SSL_PREVIEW + ssl_options_(ssl_options), +#endif /* ENABLE_HTTP_SSL_PREVIEW */ // Local vars request_headers_(request_headers), request_body_(request_body), @@ -339,8 +346,8 @@ void HttpOperation::Cleanup() case opentelemetry::ext::http::client::SessionState::Connecting: case opentelemetry::ext::http::client::SessionState::Connected: case opentelemetry::ext::http::client::SessionState::Sending: { - DispatchEvent(opentelemetry::ext::http::client::SessionState::Cancelled, - curl_easy_strerror(last_curl_result_)); + const char *message = GetCurlErrorMessage(last_curl_result_); + DispatchEvent(opentelemetry::ext::http::client::SessionState::Cancelled, message); break; } default: @@ -398,6 +405,152 @@ void HttpOperation::Cleanup() } } +/* + Support for TLS min version, TLS max version. + + To represent versions, the following symbols are needed: + + Added in CURL 7.34.0: + - CURL_SSLVERSION_TLSv1_0 + - CURL_SSLVERSION_TLSv1_1 + - CURL_SSLVERSION_TLSv1_2 + + Added in CURL 7.52.0: + - CURL_SSLVERSION_TLSv1_3 + + Added in CURL 7.54.0: + - CURL_SSLVERSION_MAX_TLSv1_0 + - CURL_SSLVERSION_MAX_TLSv1_1 + - CURL_SSLVERSION_MAX_TLSv1_2 + - CURL_SSLVERSION_MAX_TLSv1_3 + + For 7.34.0 <= CURL < 7.54.0, + we don't want to get into partial support. + + CURL 7.54.0 is required. +*/ +#if LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(7, 54, 0) +# define HAVE_TLS_VERSION +#endif + +#ifdef ENABLE_HTTP_SSL_TLS_PREVIEW +static long parse_min_ssl_version(std::string version) +{ +# ifdef HAVE_TLS_VERSION + if (version == "1.0") + { + return CURL_SSLVERSION_TLSv1_0; + } + + if (version == "1.1") + { + return CURL_SSLVERSION_TLSv1_1; + } + + if (version == "1.2") + { + return CURL_SSLVERSION_TLSv1_2; + } + + if (version == "1.3") + { + return CURL_SSLVERSION_TLSv1_3; + } +# endif + + return 0; +} + +static long parse_max_ssl_version(std::string version) +{ +# ifdef HAVE_TLS_VERSION + if (version == "1.0") + { + return CURL_SSLVERSION_MAX_TLSv1_0; + } + + if (version == "1.1") + { + return CURL_SSLVERSION_MAX_TLSv1_1; + } + + if (version == "1.2") + { + return CURL_SSLVERSION_MAX_TLSv1_2; + } + + if (version == "1.3") + { + return CURL_SSLVERSION_MAX_TLSv1_3; + } +# endif + + return 0; +} +#endif /* ENABLE_HTTP_SSL_TLS_PREVIEW */ + +const char *HttpOperation::GetCurlErrorMessage(CURLcode code) +{ + const char *message; + + if (curl_error_message_[0] != '\0') + { + // Will contain contextual data + message = curl_error_message_; + } + else + { + // Generic message + message = curl_easy_strerror(code); + } + + return message; +} + +CURLcode HttpOperation::SetCurlPtrOption(CURLoption option, void *value) +{ + CURLcode rc; + + /* + curl_easy_setopt() is a macro with variadic arguments, type unsafe. + Various SetCurlXxxOption() helpers ensure it is called with a pointer, + which can be: + - a string (const char*) + - a blob (struct curl_blob*) + - a headers chunk (curl_slist *) + */ + rc = curl_easy_setopt(curl_resource_.easy_handle, option, value); + + if (rc != CURLE_OK) + { + const char *message = GetCurlErrorMessage(rc); + OTEL_INTERNAL_LOG_ERROR("CURL, set option <" << std::to_string(option) << "> failed: <" + << message << ">"); + } + + return rc; +} + +CURLcode HttpOperation::SetCurlLongOption(CURLoption option, long value) +{ + CURLcode rc; + + /* + curl_easy_setopt() is a macro with variadic arguments, type unsafe. + SetCurlLongOption() ensures it is called with a long. + */ + rc = curl_easy_setopt(curl_resource_.easy_handle, option, value); + + if (rc != CURLE_OK) + { + const char *message = GetCurlErrorMessage(rc); + OTEL_INTERNAL_LOG_ERROR("CURL, set option <" << std::to_string(option) << "> failed: <" + << message << ">"); + } + + return rc; +} + CURLcode HttpOperation::Setup() { if (!curl_resource_.easy_handle) @@ -405,54 +558,403 @@ CURLcode HttpOperation::Setup() return CURLE_FAILED_INIT; } - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_VERBOSE, 0); + CURLcode rc; + + curl_error_message_[0] = '\0'; + curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_ERRORBUFFER, curl_error_message_); + + rc = SetCurlLongOption(CURLOPT_VERBOSE, 0L); + if (rc != CURLE_OK) + { + return rc; + } // Specify target URL - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_URL, url_.c_str()); + rc = SetCurlStrOption(CURLOPT_URL, url_.c_str()); + if (rc != CURLE_OK) + { + return rc; + } + +#ifdef ENABLE_HTTP_SSL_PREVIEW + if (ssl_options_.use_ssl) + { + /* 1 - CA CERT */ + + if (!ssl_options_.ssl_ca_cert_path.empty()) + { + const char *path = ssl_options_.ssl_ca_cert_path.c_str(); + + rc = SetCurlStrOption(CURLOPT_CAINFO, path); + if (rc != CURLE_OK) + { + return rc; + } + } + else if (!ssl_options_.ssl_ca_cert_string.empty()) + { +# if LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(7, 77, 0) + const char *data = ssl_options_.ssl_ca_cert_string.c_str(); + size_t data_len = ssl_options_.ssl_ca_cert_string.length(); + + struct curl_blob stblob; + stblob.data = const_cast(data); + stblob.len = data_len; + stblob.flags = CURL_BLOB_COPY; + + rc = SetCurlBlobOption(CURLOPT_CAINFO_BLOB, &stblob); + if (rc != CURLE_OK) + { + return rc; + } +# else + // CURL 7.77.0 required for CURLOPT_CAINFO_BLOB. + OTEL_INTERNAL_LOG_ERROR("CURL 7.77.0 required for CA CERT STRING"); + return CURLE_UNKNOWN_OPTION; +# endif + } + + /* 2 - CLIENT KEY */ + + if (!ssl_options_.ssl_client_key_path.empty()) + { + const char *path = ssl_options_.ssl_client_key_path.c_str(); + + rc = SetCurlStrOption(CURLOPT_SSLKEY, path); + if (rc != CURLE_OK) + { + return rc; + } + + rc = SetCurlStrOption(CURLOPT_SSLKEYTYPE, "PEM"); + if (rc != CURLE_OK) + { + return rc; + } + } + else if (!ssl_options_.ssl_client_key_string.empty()) + { +# if LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(7, 71, 0) + const char *data = ssl_options_.ssl_client_key_string.c_str(); + size_t data_len = ssl_options_.ssl_client_key_string.length(); + + struct curl_blob stblob; + stblob.data = const_cast(data); + stblob.len = data_len; + stblob.flags = CURL_BLOB_COPY; + + rc = SetCurlBlobOption(CURLOPT_SSLKEY_BLOB, &stblob); + if (rc != CURLE_OK) + { + return rc; + } + + rc = SetCurlStrOption(CURLOPT_SSLKEYTYPE, "PEM"); + if (rc != CURLE_OK) + { + return rc; + } +# else + // CURL 7.71.0 required for CURLOPT_SSLKEY_BLOB. + OTEL_INTERNAL_LOG_ERROR("CURL 7.71.0 required for CLIENT KEY STRING"); + return CURLE_UNKNOWN_OPTION; +# endif + } + + /* 3 - CLIENT CERT */ + + if (!ssl_options_.ssl_client_cert_path.empty()) + { + const char *path = ssl_options_.ssl_client_cert_path.c_str(); + + rc = SetCurlStrOption(CURLOPT_SSLCERT, path); + if (rc != CURLE_OK) + { + return rc; + } + + rc = SetCurlStrOption(CURLOPT_SSLCERTTYPE, "PEM"); + if (rc != CURLE_OK) + { + return rc; + } + } + else if (!ssl_options_.ssl_client_cert_string.empty()) + { +# if LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(7, 71, 0) + const char *data = ssl_options_.ssl_client_cert_string.c_str(); + size_t data_len = ssl_options_.ssl_client_cert_string.length(); + + struct curl_blob stblob; + stblob.data = const_cast(data); + stblob.len = data_len; + stblob.flags = CURL_BLOB_COPY; + + rc = SetCurlBlobOption(CURLOPT_SSLCERT_BLOB, &stblob); + if (rc != CURLE_OK) + { + return rc; + } + + rc = SetCurlStrOption(CURLOPT_SSLCERTTYPE, "PEM"); + if (rc != CURLE_OK) + { + return rc; + } +# else + // CURL 7.71.0 required for CURLOPT_SSLCERT_BLOB. + OTEL_INTERNAL_LOG_ERROR("CURL 7.71.0 required for CLIENT CERT STRING"); + return CURLE_UNKNOWN_OPTION; +# endif + } - // TODO: support ssl cert verification for https request - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_SSL_VERIFYPEER, 0); // 1L - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_SSL_VERIFYHOST, 0); // 2L +# ifdef ENABLE_HTTP_SSL_TLS_PREVIEW + /* 4 - TLS */ + + long min_ssl_version = 0; + + if (!ssl_options_.ssl_min_tls.empty()) + { +# ifdef HAVE_TLS_VERSION + min_ssl_version = parse_min_ssl_version(ssl_options_.ssl_min_tls); + + if (min_ssl_version == 0) + { + OTEL_INTERNAL_LOG_ERROR("Unknown min TLS version <" << ssl_options_.ssl_min_tls << ">"); + return CURLE_UNKNOWN_OPTION; + } +# else + OTEL_INTERNAL_LOG_ERROR("CURL 7.54.0 required for MIN TLS"); + return CURLE_UNKNOWN_OPTION; +# endif + } + + long max_ssl_version = 0; + + if (!ssl_options_.ssl_max_tls.empty()) + { +# ifdef HAVE_TLS_VERSION + max_ssl_version = parse_max_ssl_version(ssl_options_.ssl_max_tls); + + if (max_ssl_version == 0) + { + OTEL_INTERNAL_LOG_ERROR("Unknown max TLS version <" << ssl_options_.ssl_max_tls << ">"); + return CURLE_UNKNOWN_OPTION; + } +# else + OTEL_INTERNAL_LOG_ERROR("CURL 7.54.0 required for MAX TLS"); + return CURLE_UNKNOWN_OPTION; +# endif + } + + long version_range = min_ssl_version | max_ssl_version; + if (version_range != 0) + { + rc = SetCurlLongOption(CURLOPT_SSLVERSION, version_range); + if (rc != CURLE_OK) + { + return rc; + } + } + + /* 5 - CIPHER */ + + if (!ssl_options_.ssl_cipher.empty()) + { + /* TLS 1.0, 1.1, 1.2 */ + const char *cipher_list = ssl_options_.ssl_cipher.c_str(); + + rc = SetCurlStrOption(CURLOPT_SSL_CIPHER_LIST, cipher_list); + if (rc != CURLE_OK) + { + return rc; + } + } + + if (!ssl_options_.ssl_cipher_suite.empty()) + { +# if LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(7, 61, 0) + /* TLS 1.3 */ + const char *cipher_list = ssl_options_.ssl_cipher_suite.c_str(); + + rc = SetCurlStrOption(CURLOPT_TLS13_CIPHERS, cipher_list); +# else + // CURL 7.61.0 required for CURLOPT_TLS13_CIPHERS. + OTEL_INTERNAL_LOG_ERROR("CURL 7.61.0 required for CIPHER SUITE"); + return CURLE_UNKNOWN_OPTION; +# endif + + if (rc != CURLE_OK) + { + return rc; + } + } +# endif /* ENABLE_HTTP_SSL_TLS_PREVIEW */ + + if (ssl_options_.ssl_insecure_skip_verify) + { + /* 6 - DO NOT ENFORCE VERIFICATION, This is not secure. */ + rc = SetCurlLongOption(CURLOPT_USE_SSL, (long)CURLUSESSL_NONE); + if (rc != CURLE_OK) + { + return rc; + } + + rc = SetCurlLongOption(CURLOPT_SSL_VERIFYPEER, 0L); + if (rc != CURLE_OK) + { + return rc; + } + + rc = SetCurlLongOption(CURLOPT_SSL_VERIFYHOST, 0L); + if (rc != CURLE_OK) + { + return rc; + } + } + else + { + /* 6 - ENFORCE VERIFICATION */ + rc = SetCurlLongOption(CURLOPT_USE_SSL, (long)CURLUSESSL_ALL); + if (rc != CURLE_OK) + { + return rc; + } + + rc = SetCurlLongOption(CURLOPT_SSL_VERIFYPEER, 1L); + if (rc != CURLE_OK) + { + return rc; + } + + rc = SetCurlLongOption(CURLOPT_SSL_VERIFYHOST, 2L); + if (rc != CURLE_OK) + { + return rc; + } + } + } + else +#endif /* ENABLE_HTTP_SSL_PREVIEW */ + { + rc = SetCurlLongOption(CURLOPT_SSL_VERIFYPEER, 0L); + if (rc != CURLE_OK) + { + return rc; + } + + rc = SetCurlLongOption(CURLOPT_SSL_VERIFYHOST, 0L); + if (rc != CURLE_OK) + { + return rc; + } + } if (curl_resource_.headers_chunk != nullptr) { - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_HTTPHEADER, curl_resource_.headers_chunk); + rc = SetCurlListOption(CURLOPT_HTTPHEADER, curl_resource_.headers_chunk); + if (rc != CURLE_OK) + { + return rc; + } } // TODO: control local port to use // curl_easy_setopt(curl, CURLOPT_LOCALPORT, dcf_port); - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_TIMEOUT_MS, http_conn_timeout_.count()); + rc = SetCurlLongOption(CURLOPT_TIMEOUT_MS, http_conn_timeout_.count()); + if (rc != CURLE_OK) + { + return rc; + } // abort if slower than 4kb/sec during 30 seconds - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_LOW_SPEED_TIME, 30L); - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_LOW_SPEED_LIMIT, 4096); + rc = SetCurlLongOption(CURLOPT_LOW_SPEED_TIME, 30L); + if (rc != CURLE_OK) + { + return rc; + } + + rc = SetCurlLongOption(CURLOPT_LOW_SPEED_LIMIT, 4096L); + if (rc != CURLE_OK) + { + return rc; + } + if (reuse_connection_) { - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_FRESH_CONNECT, 0L); - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_FORBID_REUSE, 0L); + rc = SetCurlLongOption(CURLOPT_FRESH_CONNECT, 0L); + if (rc != CURLE_OK) + { + return rc; + } + + rc = SetCurlLongOption(CURLOPT_FORBID_REUSE, 0L); + if (rc != CURLE_OK) + { + return rc; + } } else { - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_FRESH_CONNECT, 1L); - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_FORBID_REUSE, 1L); + rc = SetCurlLongOption(CURLOPT_FRESH_CONNECT, 1L); + if (rc != CURLE_OK) + { + return rc; + } + rc = SetCurlLongOption(CURLOPT_FORBID_REUSE, 1L); + if (rc != CURLE_OK) + { + return rc; + } } if (is_raw_response_) { - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_HEADER, true); - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_WRITEFUNCTION, - (void *)&HttpOperation::WriteMemoryCallback); - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_WRITEDATA, (void *)this); + rc = SetCurlLongOption(CURLOPT_HEADER, 1L); + if (rc != CURLE_OK) + { + return rc; + } + + rc = SetCurlPtrOption(CURLOPT_WRITEFUNCTION, (void *)&HttpOperation::WriteMemoryCallback); + if (rc != CURLE_OK) + { + return rc; + } + + rc = SetCurlPtrOption(CURLOPT_WRITEDATA, (void *)this); + if (rc != CURLE_OK) + { + return rc; + } } else { - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_WRITEFUNCTION, - (void *)&HttpOperation::WriteVectorBodyCallback); - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_WRITEDATA, (void *)this); - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_HEADERFUNCTION, - (void *)&HttpOperation::WriteVectorHeaderCallback); - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_HEADERDATA, (void *)this); + rc = SetCurlPtrOption(CURLOPT_WRITEFUNCTION, (void *)&HttpOperation::WriteVectorBodyCallback); + if (rc != CURLE_OK) + { + return rc; + } + + rc = SetCurlPtrOption(CURLOPT_WRITEDATA, (void *)this); + if (rc != CURLE_OK) + { + return rc; + } + + rc = + SetCurlPtrOption(CURLOPT_HEADERFUNCTION, (void *)&HttpOperation::WriteVectorHeaderCallback); + if (rc != CURLE_OK) + { + return rc; + } + + rc = SetCurlPtrOption(CURLOPT_HEADERDATA, (void *)this); + if (rc != CURLE_OK) + { + return rc; + } } // TODO: only two methods supported for now - POST and GET @@ -461,12 +963,35 @@ CURLcode HttpOperation::Setup() // Request buffer const curl_off_t req_size = static_cast(request_body_.size()); // POST - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_POST, 1L); - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_POSTFIELDS, NULL); - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_POSTFIELDSIZE_LARGE, req_size); - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_READFUNCTION, - (void *)&HttpOperation::ReadMemoryCallback); - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_READDATA, (void *)this); + rc = SetCurlLongOption(CURLOPT_POST, 1L); + if (rc != CURLE_OK) + { + return rc; + } + + rc = SetCurlStrOption(CURLOPT_POSTFIELDS, NULL); + if (rc != CURLE_OK) + { + return rc; + } + + rc = SetCurlLongOption(CURLOPT_POSTFIELDSIZE_LARGE, req_size); + if (rc != CURLE_OK) + { + return rc; + } + + rc = SetCurlPtrOption(CURLOPT_READFUNCTION, (void *)&HttpOperation::ReadMemoryCallback); + if (rc != CURLE_OK) + { + return rc; + } + + rc = SetCurlPtrOption(CURLOPT_READDATA, (void *)this); + if (rc != CURLE_OK) + { + return rc; + } } else if (method_ == opentelemetry::ext::http::client::Method::Get) { @@ -474,23 +999,48 @@ CURLcode HttpOperation::Setup() } else { + OTEL_INTERNAL_LOG_ERROR("Unexpected HTTP method"); return CURLE_UNSUPPORTED_PROTOCOL; } #if LIBCURL_VERSION_NUM >= 0x072000 - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_XFERINFOFUNCTION, - (void *)&HttpOperation::OnProgressCallback); - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_XFERINFODATA, (void *)this); + rc = SetCurlPtrOption(CURLOPT_XFERINFOFUNCTION, (void *)&HttpOperation::OnProgressCallback); + if (rc != CURLE_OK) + { + return rc; + } + + rc = SetCurlPtrOption(CURLOPT_XFERINFODATA, (void *)this); + if (rc != CURLE_OK) + { + return rc; + } #else - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_PROGRESSFUNCTION, - (void *)&HttpOperation::OnProgressCallback); - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_PROGRESSDATA, (void *)this); + rc = SetCurlPtrOption(CURLOPT_PROGRESSFUNCTION, (void *)&HttpOperation::OnProgressCallback); + if (rc != CURLE_OK) + { + return rc; + } + + rc = SetCurlPtrOption(CURLOPT_PROGRESSDATA, (void *)this); + if (rc != CURLE_OK) + { + return rc; + } #endif #if LIBCURL_VERSION_NUM >= 0x075000 - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_PREREQFUNCTION, - (void *)&HttpOperation::PreRequestCallback); - curl_easy_setopt(curl_resource_.easy_handle, CURLOPT_PREREQDATA, (void *)this); + rc = SetCurlPtrOption(CURLOPT_PREREQFUNCTION, (void *)&HttpOperation::PreRequestCallback); + if (rc != CURLE_OK) + { + return rc; + } + + rc = SetCurlPtrOption(CURLOPT_PREREQDATA, (void *)this); + if (rc != CURLE_OK) + { + return rc; + } #endif return CURLE_OK; @@ -509,8 +1059,8 @@ CURLcode HttpOperation::Send() last_curl_result_ = Setup(); if (last_curl_result_ != CURLE_OK) { - DispatchEvent(opentelemetry::ext::http::client::SessionState::ConnectFailed, - curl_easy_strerror(last_curl_result_)); + const char *message = GetCurlErrorMessage(last_curl_result_); + DispatchEvent(opentelemetry::ext::http::client::SessionState::ConnectFailed, message); return last_curl_result_; } @@ -553,6 +1103,8 @@ CURLcode HttpOperation::SendAsync(Session *session, std::function unreadable.pem +chmod 0 unreadable.pem + +# Needed to copy this key inside docker (different owner) +chmod +r server_cert-key.pem + +# Debug +ls -l + diff --git a/functional/cert/server_csr.json b/functional/cert/server_csr.json new file mode 100644 index 0000000000..39a5a64727 --- /dev/null +++ b/functional/cert/server_csr.json @@ -0,0 +1,12 @@ +{ + "hosts": ["localhost", "127.0.0.1"], + "key": { + "algo": "rsa", + "size": 2048 + }, + "names": [ + { + "O": "OpenTelemetry Server Example" + } + ] +} diff --git a/functional/cert/server_csr_b.json b/functional/cert/server_csr_b.json new file mode 100644 index 0000000000..b54e7c9bb9 --- /dev/null +++ b/functional/cert/server_csr_b.json @@ -0,0 +1,12 @@ +{ + "hosts": ["localhost", "127.0.0.1"], + "key": { + "algo": "rsa", + "size": 2048 + }, + "names": [ + { + "O": "OpenTelemetry Server Example B" + } + ] +} diff --git a/functional/otlp/CMakeLists.txt b/functional/otlp/CMakeLists.txt new file mode 100644 index 0000000000..39b25cc324 --- /dev/null +++ b/functional/otlp/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +include_directories(${CMAKE_SOURCE_DIR}/exporters/otlp/include) + +if(WITH_OTLP_HTTP) + add_executable(func_otlp_http func_http_main.cc) + target_link_libraries(func_otlp_http ${CMAKE_THREAD_LIBS_INIT} + opentelemetry_trace opentelemetry_exporter_otlp_http) +endif() diff --git a/functional/otlp/Dockerfile b/functional/otlp/Dockerfile new file mode 100644 index 0000000000..79e09d61ba --- /dev/null +++ b/functional/otlp/Dockerfile @@ -0,0 +1,7 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +FROM otel/opentelemetry-collector +COPY . . +CMD ["--config", "/otel-cpp/otel-config.yaml"] +EXPOSE 4318 diff --git a/functional/otlp/func_http_main.cc b/functional/otlp/func_http_main.cc new file mode 100644 index 0000000000..72fbb5e21c --- /dev/null +++ b/functional/otlp/func_http_main.cc @@ -0,0 +1,1810 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/exporters/otlp/otlp_http_exporter_factory.h" +#include "opentelemetry/exporters/otlp/otlp_http_exporter_options.h" +#include "opentelemetry/sdk/common/global_log_handler.h" +#include "opentelemetry/sdk/trace/simple_processor_factory.h" +#include "opentelemetry/sdk/trace/tracer_provider_factory.h" +#include "opentelemetry/trace/provider.h" + +#include + +namespace trace = opentelemetry::trace; +namespace trace_sdk = opentelemetry::sdk::trace; +namespace otlp = opentelemetry::exporter::otlp; +namespace nostd = opentelemetry::nostd; + +namespace internal_log = opentelemetry::sdk::common::internal_log; + +const int TEST_PASSED = 0; +const int TEST_FAILED = 1; + +/* + Command line parameters. +*/ + +enum test_mode +{ + MODE_NONE, + MODE_HTTP, + MODE_HTTPS +}; + +bool opt_help = false; +bool opt_list = false; +bool opt_debug = false; +bool opt_secure = false; +// HTTPS by default +std::string opt_endpoint = "https://localhost:4318/v1/traces"; +std::string opt_cert_dir; +std::string opt_test_name; +test_mode opt_mode = MODE_NONE; + +/* + Log parsing +*/ + +struct TestResult +{ + bool found_connection_failed = false; + bool found_connection_refused = false; + bool found_request_send_failure = false; + bool found_export_error = false; + bool found_export_success = false; + + void reset() + { + found_connection_failed = false; + found_connection_refused = false; + found_request_send_failure = false; + found_export_error = false; + found_export_success = false; + } +}; + +struct TestResult g_test_result; + +void parse_error_msg(TestResult *result, std::string msg) +{ + static std::string connection_failed("Session state: connection failed."); + + if (msg.find(connection_failed) != std::string::npos) + { + result->found_connection_failed = true; + } + + static std::string connection_refused("Connection refused"); + + if (msg.find(connection_refused) != std::string::npos) + { + result->found_connection_refused = true; + } + + static std::string request_send_failed("Session state: request send failed."); + + if (msg.find(request_send_failed) != std::string::npos) + { + result->found_request_send_failure = true; + } + + static std::string export_failed("ERROR: Export 1 trace span(s) error: 1"); + + if (msg.find(export_failed) != std::string::npos) + { + result->found_export_error = true; + } +} + +void parse_warning_msg(TestResult * /* result */, std::string /* msg */) {} + +void parse_info_msg(TestResult * /* result */, std::string /* msg */) {} + +void parse_debug_msg(TestResult *result, std::string msg) +{ + static std::string export_success("Export 1 trace span(s) success"); + + if (msg.find(export_success) != std::string::npos) + { + result->found_export_success = true; + } +} + +class TestLogHandler : public opentelemetry::sdk::common::internal_log::LogHandler +{ +public: + void Handle(opentelemetry::sdk::common::internal_log::LogLevel level, + const char * /* file */, + int /* line */, + const char *msg, + const opentelemetry::sdk::common::AttributeMap & /* attributes */) noexcept override + { + if (msg == nullptr) + { + msg = ""; + } + + switch (level) + { + case opentelemetry::sdk::common::internal_log::LogLevel::Error: + std::cout << " - [E] " << msg << std::endl; + parse_error_msg(&g_test_result, msg); + break; + case opentelemetry::sdk::common::internal_log::LogLevel::Warning: + std::cout << " - [W] " << msg << std::endl; + parse_warning_msg(&g_test_result, msg); + break; + case opentelemetry::sdk::common::internal_log::LogLevel::Info: + std::cout << " - [I] " << msg << std::endl; + parse_info_msg(&g_test_result, msg); + break; + case opentelemetry::sdk::common::internal_log::LogLevel::Debug: + std::cout << " - [D] " << msg << std::endl; + parse_debug_msg(&g_test_result, msg); + break; + } + } +}; + +void init(const otlp::OtlpHttpExporterOptions &opts) +{ + // Create OTLP exporter instance + auto exporter = otlp::OtlpHttpExporterFactory::Create(opts); + auto processor = trace_sdk::SimpleSpanProcessorFactory::Create(std::move(exporter)); + std::shared_ptr provider = + trace_sdk::TracerProviderFactory::Create(std::move(processor)); + // Set the global trace provider + trace::Provider::SetTracerProvider(provider); +} + +void payload() +{ + static const nostd::string_view k_tracer_name("func_test"); + static const nostd::string_view k_span_name("func_http_main"); + static const nostd::string_view k_attr_test_name("test_name"); + + auto provider = trace::Provider::GetTracerProvider(); + auto tracer = provider->GetTracer(k_tracer_name, "1.0"); + + auto span = tracer->StartSpan(k_span_name); + span->SetAttribute(k_attr_test_name, opt_test_name); + span->End(); + + tracer->ForceFlushWithMicroseconds(1000000); +} + +void cleanup() +{ + std::shared_ptr none; + trace::Provider::SetTracerProvider(none); +} + +void instrumented_payload(const otlp::OtlpHttpExporterOptions &opts) +{ + g_test_result.reset(); + init(opts); + payload(); + cleanup(); +} + +void usage(FILE *out) +{ + static const char *msg = + "Usage: func_otlp_http [options] test_name\n" + "Valid options are:\n" + " --help Print this help\n" + " --list List test names\n" + " --endpoint url OTLP HTTP endpoint (https://localhost:4318/v1/traces by default)\n" + " --cert-dir dir Directory that contains test ssl certificates\n" + " --mode mode Test server mode (used to verify expected results)\n" + " - none: no endpoint\n" + " - http: http endpoint\n" + " - https: https endpoint\n"; + fprintf(out, "%s", msg); +} + +int parse_args(int argc, char *argv[]) +{ + int remaining_argc = argc; + char **remaining_argv = argv; + + while (remaining_argc > 0) + { + if (strcmp(*remaining_argv, "--help") == 0) + { + opt_help = true; + return 0; + } + + if (strcmp(*remaining_argv, "--list") == 0) + { + opt_list = true; + return 0; + } + + if (strcmp(*remaining_argv, "--debug") == 0) + { + opt_debug = true; + remaining_argc--; + remaining_argv++; + continue; + } + + if (remaining_argc >= 2) + { + if (strcmp(*remaining_argv, "--cert-dir") == 0) + { + remaining_argc--; + remaining_argv++; + opt_cert_dir = *remaining_argv; + remaining_argc--; + remaining_argv++; + continue; + } + + if (strcmp(*remaining_argv, "--endpoint") == 0) + { + remaining_argc--; + remaining_argv++; + opt_endpoint = *remaining_argv; + remaining_argc--; + remaining_argv++; + continue; + } + + if (strcmp(*remaining_argv, "--mode") == 0) + { + remaining_argc--; + remaining_argv++; + std::string mode = *remaining_argv; + remaining_argc--; + remaining_argv++; + + if (mode == "none") + { + opt_mode = MODE_NONE; + } + else if (mode == "http") + { + opt_mode = MODE_HTTP; + } + else if (mode == "https") + { + opt_mode = MODE_HTTPS; + } + else + { + // Unknown mode + return 2; + } + + continue; + } + } + + opt_test_name = *remaining_argv; + remaining_argc--; + remaining_argv++; + + if (remaining_argc) + { + // Unknown option + return 1; + } + } + + return 0; +} + +typedef int (*test_func_t)(); + +struct test_case +{ + std::string m_name; + test_func_t m_func; +}; + +int test_basic(); + +#ifdef ENABLE_OTLP_HTTP_SSL_PREVIEW +int test_cert_not_found(); +int test_cert_invalid(); +int test_cert_unreadable(); +int test_cert_ok(); +int test_client_cert_not_found(); +int test_client_cert_invalid(); +int test_client_cert_unreadable(); +int test_client_cert_no_key(); +int test_client_key_not_found(); +int test_client_key_invalid(); +int test_client_key_unreadable(); +int test_client_key_ok(); +#endif /* ENABLE_OTLP_HTTP_SSL_PREVIEW */ + +#ifdef ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW +int test_min_tls_unknown(); +int test_min_tls_10(); +int test_min_tls_11(); +int test_min_tls_12(); +int test_min_tls_13(); +int test_max_tls_unknown(); +int test_max_tls_10(); +int test_max_tls_11(); +int test_max_tls_12(); +int test_max_tls_13(); +int test_range_tls_10(); +int test_range_tls_11(); +int test_range_tls_12(); +int test_range_tls_13(); +int test_range_tls_10_11(); +int test_range_tls_10_12(); +int test_range_tls_10_13(); +int test_range_tls_11_10(); +int test_range_tls_11_12(); +int test_range_tls_11_13(); +int test_range_tls_12_10(); +int test_range_tls_12_11(); +int test_range_tls_12_13(); +int test_range_tls_13_10(); +int test_range_tls_13_11(); +int test_range_tls_13_12(); +#endif /* ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW */ + +static const test_case all_tests[] = {{"basic", test_basic}, +#ifdef ENABLE_OTLP_HTTP_SSL_PREVIEW + {"cert-not-found", test_cert_not_found}, + {"cert-invalid", test_cert_invalid}, + {"cert-unreadable", test_cert_unreadable}, + {"cert-ok", test_cert_ok}, + {"client-cert-not-found", test_client_cert_not_found}, + {"client-cert-invalid", test_client_cert_invalid}, + {"client-cert-unreadable", test_client_cert_unreadable}, + {"client-cert-no-key", test_client_cert_no_key}, + {"client-key-not-found", test_client_key_not_found}, + {"client-key-invalid", test_client_key_invalid}, + {"client-key-unreadable", test_client_key_unreadable}, + {"client-key-ok", test_client_key_ok}, +#endif /* ENABLE_OTLP_HTTP_SSL_PREVIEW */ + +#ifdef ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW + {"min-tls-unknown", test_min_tls_unknown}, + {"min-tls-10", test_min_tls_10}, + {"min-tls-11", test_min_tls_11}, + {"min-tls-12", test_min_tls_12}, + {"min-tls-13", test_min_tls_13}, + {"max-tls-unknown", test_max_tls_unknown}, + {"max-tls-10", test_max_tls_10}, + {"max-tls-11", test_max_tls_11}, + {"max-tls-12", test_max_tls_12}, + {"max-tls-13", test_max_tls_13}, + {"range-tls-10", test_range_tls_10}, + {"range-tls-11", test_range_tls_11}, + {"range-tls-12", test_range_tls_12}, + {"range-tls-13", test_range_tls_13}, + {"range-tls-10-11", test_range_tls_10_11}, + {"range-tls-10-12", test_range_tls_10_12}, + {"range-tls-10-13", test_range_tls_10_13}, + {"range-tls-11-10", test_range_tls_11_10}, + {"range-tls-11-12", test_range_tls_11_12}, + {"range-tls-11-13", test_range_tls_11_13}, + {"range-tls-12-10", test_range_tls_12_10}, + {"range-tls-12-11", test_range_tls_12_11}, + {"range-tls-12-13", test_range_tls_12_13}, + {"range-tls-13-10", test_range_tls_13_10}, + {"range-tls-13-11", test_range_tls_13_11}, + {"range-tls-13-12", test_range_tls_13_12}, +#endif /* ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW */ + {"", nullptr}}; + +void list_test_cases() +{ + const test_case *current = all_tests; + + while (current->m_func != nullptr) + { + std::cout << current->m_name << std::endl; + current++; + } +} + +int run_test_case(std::string name) +{ + const test_case *current = all_tests; + + while (current->m_func != nullptr) + { + if (current->m_name == name) + { + int rc = current->m_func(); + return rc; + } + current++; + } + + std::cerr << "Unknown test <" << name << ">" << std::endl; + return 1; +} + +int main(int argc, char *argv[]) +{ + // Program name + argc--; + argv++; + + int rc = parse_args(argc, argv); + + if (rc != 0) + { + usage(stderr); + return 1; + } + + if (opt_help) + { + usage(stdout); + return 0; + } + + if (opt_list) + { + list_test_cases(); + return 0; + } + + if (opt_endpoint.find("https:") != std::string::npos) + { + opt_secure = true; + } + else + { + opt_secure = false; + } + + opentelemetry::nostd::shared_ptr log_handler(new TestLogHandler); + + internal_log::GlobalLogHandler::SetLogHandler(log_handler); + internal_log::GlobalLogHandler::SetLogLevel(internal_log::LogLevel::Debug); + + rc = run_test_case(opt_test_name); + return rc; +} + +void set_common_opts(otlp::OtlpHttpExporterOptions &opts) +{ + opts.url = opt_endpoint; + + if (opt_debug) + { + opts.console_debug = true; + } + +#ifdef ENABLE_ASYNC_EXPORT + // Work around, ASYNC export not working. + opts.max_concurrent_requests = 0; +#endif +} + +int expect_connection_failed() +{ + if (g_test_result.found_export_error && g_test_result.found_connection_failed) + { + return TEST_PASSED; + } + return TEST_FAILED; +} + +int expect_success() +{ + if (g_test_result.found_export_success) + { + return TEST_PASSED; + } + return TEST_FAILED; +} + +int expect_request_send_failed() +{ + if (g_test_result.found_export_error && g_test_result.found_request_send_failure) + { + return TEST_PASSED; + } + return TEST_FAILED; +} + +int expect_export_failed() +{ + /* + Can not test exact root cause: + - connect failed ? + - send request failed ? + - exact error message ? + so only verifying export failed. + */ + + if (g_test_result.found_export_error) + { + return TEST_PASSED; + } + return TEST_FAILED; +} + +int test_basic() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + if (opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_connection_failed(); + } + + return expect_connection_failed(); +} + +#ifdef ENABLE_OTLP_HTTP_SSL_PREVIEW + +int test_cert_not_found() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/no-such-file.pem"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + return expect_connection_failed(); +} + +int test_cert_invalid() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/garbage.pem"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + return expect_connection_failed(); +} + +int test_cert_unreadable() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/unreadable.pem"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + return expect_connection_failed(); +} + +int test_cert_ok() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + if (opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_connection_failed(); + } + + return expect_success(); +} + +int test_client_cert_not_found() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/no-such-file.pem"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + return expect_connection_failed(); +} + +int test_client_cert_invalid() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/garbage.pem"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + return expect_connection_failed(); +} + +int test_client_cert_unreadable() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/unreadable.pem"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + return expect_connection_failed(); +} + +int test_client_cert_no_key() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + return expect_connection_failed(); +} + +int test_client_key_not_found() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/no-such-file.pem"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + return expect_connection_failed(); +} + +int test_client_key_invalid() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/garbage.pem"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + return expect_connection_failed(); +} + +int test_client_key_unreadable() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/unreadable.pem"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + return expect_connection_failed(); +} + +int test_client_key_ok() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + if (opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_connection_failed(); + } + + return expect_success(); +} +#endif /* ENABLE_OTLP_HTTP_SSL_PREVIEW */ + +#ifdef ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW + +int test_min_tls_unknown() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_min_tls = "99.99"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + return expect_connection_failed(); +} + +int test_min_tls_10() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_min_tls = "1.0"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + if (opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_connection_failed(); + } + + return expect_success(); +} + +int test_min_tls_11() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_min_tls = "1.1"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + if (opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_connection_failed(); + } + + return expect_success(); +} + +int test_min_tls_12() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_min_tls = "1.2"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + if (opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_connection_failed(); + } + + return expect_success(); +} + +int test_min_tls_13() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_min_tls = "1.3"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + if (opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_connection_failed(); + } + + return expect_success(); +} + +int test_max_tls_unknown() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_max_tls = "99.99"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + return expect_connection_failed(); +} + +int test_max_tls_10() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_max_tls = "1.0"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + if (opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_export_failed(); + } + + // No support for TLS 1.0 + return expect_connection_failed(); +} + +int test_max_tls_11() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_max_tls = "1.1"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + if (opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_export_failed(); + } + + // No support for TLS 1.1 + return expect_connection_failed(); +} + +int test_max_tls_12() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_max_tls = "1.2"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + if (opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_connection_failed(); + } + + return expect_success(); +} + +int test_max_tls_13() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_max_tls = "1.3"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + if (opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_connection_failed(); + } + + return expect_success(); +} + +int test_range_tls_10() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_min_tls = "1.0"; + opts.ssl_max_tls = "1.0"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + if (opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_connection_failed(); + } + + // No support for TLS 1.0 + return expect_connection_failed(); +} + +int test_range_tls_11() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_min_tls = "1.1"; + opts.ssl_max_tls = "1.1"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + if (opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_connection_failed(); + } + + // No support for TLS 1.0 + return expect_connection_failed(); +} + +int test_range_tls_12() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_min_tls = "1.2"; + opts.ssl_max_tls = "1.2"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + if (opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_connection_failed(); + } + + return expect_success(); +} + +int test_range_tls_13() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_min_tls = "1.3"; + opts.ssl_max_tls = "1.3"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + if (opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_connection_failed(); + } + + return expect_success(); +} + +int test_range_tls_10_11() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_min_tls = "1.0"; + opts.ssl_max_tls = "1.1"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + if (opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_connection_failed(); + } + + // No support for TLS 1.0, TLS 1.1 + return expect_connection_failed(); +} + +int test_range_tls_10_12() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_min_tls = "1.0"; + opts.ssl_max_tls = "1.2"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + if (opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_connection_failed(); + } + + return expect_success(); +} + +int test_range_tls_10_13() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_min_tls = "1.0"; + opts.ssl_max_tls = "1.3"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + if (opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_connection_failed(); + } + + return expect_success(); +} + +int test_range_tls_11_10() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_min_tls = "1.1"; + opts.ssl_max_tls = "1.0"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + // Impossible + return expect_connection_failed(); +} + +int test_range_tls_11_12() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_min_tls = "1.1"; + opts.ssl_max_tls = "1.2"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + if (opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_connection_failed(); + } + + return expect_success(); +} + +int test_range_tls_11_13() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_min_tls = "1.1"; + opts.ssl_max_tls = "1.3"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + if (opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_connection_failed(); + } + + return expect_success(); +} + +int test_range_tls_12_10() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_min_tls = "1.2"; + opts.ssl_max_tls = "1.0"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + // Impossible + return expect_connection_failed(); +} + +int test_range_tls_12_11() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_min_tls = "1.2"; + opts.ssl_max_tls = "1.1"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + // Impossible + return expect_connection_failed(); +} + +int test_range_tls_12_13() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_min_tls = "1.2"; + opts.ssl_max_tls = "1.3"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + if (opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_connection_failed(); + } + + return expect_success(); +} + +int test_range_tls_13_10() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_min_tls = "1.3"; + opts.ssl_max_tls = "1.0"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + // Impossible + return expect_connection_failed(); +} + +int test_range_tls_13_11() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_min_tls = "1.3"; + opts.ssl_max_tls = "1.1"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + // Impossible + return expect_connection_failed(); +} + +int test_range_tls_13_12() +{ + otlp::OtlpHttpExporterOptions opts; + + set_common_opts(opts); + opts.ssl_ca_cert_path = opt_cert_dir + "/ca.pem"; + opts.ssl_client_cert_path = opt_cert_dir + "/client_cert.pem"; + opts.ssl_client_key_path = opt_cert_dir + "/client_cert-key.pem"; + opts.ssl_min_tls = "1.3"; + opts.ssl_max_tls = "1.2"; + + instrumented_payload(opts); + + if (opt_mode == MODE_NONE) + { + return expect_connection_failed(); + } + + if (!opt_secure && (opt_mode == MODE_HTTP)) + { + return expect_success(); + } + + if (!opt_secure && (opt_mode == MODE_HTTPS)) + { + return expect_export_failed(); + } + + // Impossible + return expect_connection_failed(); +} + +#endif /* ENABLE_OTLP_HTTP_SSL_TLS_PREVIEW */ diff --git a/functional/otlp/otel-config-http.yaml b/functional/otlp/otel-config-http.yaml new file mode 100644 index 0000000000..39c264c747 --- /dev/null +++ b/functional/otlp/otel-config-http.yaml @@ -0,0 +1,32 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +# +# To use directly: +# otelcol --config ... +# + +receivers: + otlp: + protocols: + http: + +processors: + batch: + memory_limiter: + # 75% of maximum memory up to 4G + limit_mib: 1536 + # 25% of limit up to 2G + spike_limit_mib: 512 + check_interval: 5s + +exporters: + logging: + loglevel: debug + +service: + pipelines: + traces: + receivers: [otlp] + processors: [memory_limiter, batch] + exporters: [logging] diff --git a/functional/otlp/otel-config-https.yaml b/functional/otlp/otel-config-https.yaml new file mode 100644 index 0000000000..611bba828f --- /dev/null +++ b/functional/otlp/otel-config-https.yaml @@ -0,0 +1,39 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +# +# To use directly: +# otelcol --config ... +# + +receivers: + otlp: + protocols: + http: + tls: + ca_file: ../cert/ca.pem + cert_file: ../cert/server_cert.pem + key_file: ../cert/server_cert-key.pem + min_version: "1.0" + max_version: "1.3" + + +processors: + batch: + memory_limiter: + # 75% of maximum memory up to 4G + limit_mib: 1536 + # 25% of limit up to 2G + spike_limit_mib: 512 + check_interval: 5s + +exporters: + logging: + loglevel: debug + +service: + pipelines: + traces: + receivers: [otlp] + processors: [memory_limiter, batch] + exporters: [logging] diff --git a/functional/otlp/otel-docker-config-http.yaml b/functional/otlp/otel-docker-config-http.yaml new file mode 100644 index 0000000000..f8e5ad45d3 --- /dev/null +++ b/functional/otlp/otel-docker-config-http.yaml @@ -0,0 +1,31 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +# +# To use from a docker container +# + +receivers: + otlp: + protocols: + http: + +processors: + batch: + memory_limiter: + # 75% of maximum memory up to 4G + limit_mib: 1536 + # 25% of limit up to 2G + spike_limit_mib: 512 + check_interval: 5s + +exporters: + logging: + loglevel: debug + +service: + pipelines: + traces: + receivers: [otlp] + processors: [memory_limiter, batch] + exporters: [logging] diff --git a/functional/otlp/otel-docker-config-https.yaml b/functional/otlp/otel-docker-config-https.yaml new file mode 100644 index 0000000000..9b3422bf5e --- /dev/null +++ b/functional/otlp/otel-docker-config-https.yaml @@ -0,0 +1,38 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +# +# To use inside a docker container +# + +receivers: + otlp: + protocols: + http: + tls: + ca_file: /otel-cpp/ca.pem + cert_file: /otel-cpp/server_cert.pem + key_file: /otel-cpp/server_cert-key.pem + min_version: "1.0" + max_version: "1.3" + + +processors: + batch: + memory_limiter: + # 75% of maximum memory up to 4G + limit_mib: 1536 + # 25% of limit up to 2G + spike_limit_mib: 512 + check_interval: 5s + +exporters: + logging: + loglevel: debug + +service: + pipelines: + traces: + receivers: [otlp] + processors: [memory_limiter, batch] + exporters: [logging] diff --git a/functional/otlp/run_test.sh b/functional/otlp/run_test.sh new file mode 100755 index 0000000000..3a0e055092 --- /dev/null +++ b/functional/otlp/run_test.sh @@ -0,0 +1,127 @@ +#!/bin/bash + +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +# set -e + +# To run tests in a local dev environment: +# - make sure docker is running +# - set BUILD_DIR to the top level build directory, + +[ -z "${BUILD_DIR}" ] && export BUILD_DIR=$HOME/build + +export CERT_DIR=../cert + +export TEST_BIN_DIR=${BUILD_DIR}/functional/otlp/ + +${TEST_BIN_DIR}/func_otlp_http --list > test_list.txt + +# +# Prepare docker image +# + +docker build -t otelcpp-func-test . + +echo "REPORT:" > report.log + +# +# MODE 'NONE' +# + +export SERVER_MODE="none" +./run_test_mode.sh + +# +# MODE 'HTTP' +# + +echo "" +echo "###############################################################" +echo "Starting otelcol --config otel-config-http.yaml" +echo "###############################################################" +echo "" + + +docker run -d \ + -v `pwd`/otel-docker-config-http.yaml:/otel-cpp/otel-config.yaml \ + -p 4318:4318 \ + --name otelcpp-test-http \ + otelcpp-func-test + +sleep 5; + +export SERVER_MODE="http" +./run_test_mode.sh + +echo "" +echo "###############################################################" +echo "Stopping otelcol (http)" +echo "###############################################################" +echo "" + +docker stop otelcpp-test-http +docker rm otelcpp-test-http + +# +# MODE 'SSL' +# + +echo "" +echo "###############################################################" +echo "Starting otelcol --config otel-config-https.yaml" +echo "###############################################################" +echo "" + +docker run -d \ + -v `pwd`/otel-docker-config-https.yaml:/otel-cpp/otel-config.yaml \ + -v `pwd`/../cert/ca.pem:/otel-cpp/ca.pem \ + -v `pwd`/../cert/server_cert.pem:/otel-cpp/server_cert.pem \ + -v `pwd`/../cert/server_cert-key.pem:/otel-cpp/server_cert-key.pem \ + -p 4318:4318 \ + --name otelcpp-test-https \ + otelcpp-func-test + +sleep 5; + +export SERVER_MODE="https" +./run_test_mode.sh + +echo "" +echo "###############################################################" +echo "Stopping otelcol (https)" +echo "###############################################################" +echo "" + +docker stop otelcpp-test-https +docker rm otelcpp-test-https + +echo "" +echo "###############################################################" +echo "TEST REPORT" +echo "###############################################################" +echo "" + +cat report.log + +export PASSED_COUNT=`grep -c "PASSED" report.log` +export FAILED_COUNT=`grep -c "FAILED" report.log` + +echo "" +echo "###############################################################" +echo "TEST VERDICT: ${PASSED_COUNT} PASSED, ${FAILED_COUNT} FAILED" +echo "###############################################################" +echo "" + +if [ ${FAILED_COUNT} != "0" ]; then + # + # CI FAILED + # + + exit 1 +fi; + +# +# CI PASSED +# +exit 0 diff --git a/functional/otlp/run_test_mode.sh b/functional/otlp/run_test_mode.sh new file mode 100755 index 0000000000..fab59108d3 --- /dev/null +++ b/functional/otlp/run_test_mode.sh @@ -0,0 +1,74 @@ +#!/bin/bash + +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +# +# This script can be invoked as follows: +# +# export SERVER_MODE="none" (default) +# No collector listening on endpoint. +# +# export SERVER_MODE="http" +# Http collector listening on endpoint. +# +# export SERVER_MODE="https" +# Https collector listening on endpoint. +# + +# set -e + +[ -z "${BUILD_DIR}" ] && export BUILD_DIR=$HOME/build + +[ -z "${SERVER_MODE}" ] && export SERVER_MODE="none" + +export CERT_DIR=../cert + +export TEST_BIN_DIR=${BUILD_DIR}/functional/otlp/ + +${TEST_BIN_DIR}/func_otlp_http --list > test_list.txt + +export TEST_FULL_NAME="" + +# +# Connect with no security +# + +export TEST_ENDPOINT="http://localhost:4318/v1/traces" +export TEST_RUN="insecure" + +for T in `cat test_list.txt` +do + echo "=====================================================================" + echo "Running test ${T} on ${TEST_RUN} ${TEST_ENDPOINT} with server ${SERVER_MODE}" + TEST_FULL_NAME="${T}-${TEST_RUN}-${SERVER_MODE}" + ${TEST_BIN_DIR}/func_otlp_http --debug --mode ${SERVER_MODE} --cert-dir ${CERT_DIR} --endpoint ${TEST_ENDPOINT} ${T} + RC=$? + if [ ${RC} -eq 0 ]; then + echo "TEST ${TEST_FULL_NAME}: PASSED" | tee -a report.log + else + echo "TEST ${TEST_FULL_NAME}: FAILED" | tee -a report.log + fi +done + +# +# Connect with security +# + +export TEST_ENDPOINT="https://localhost:4318/v1/traces" +export TEST_RUN="secure" + +for T in `cat test_list.txt` +do + echo "=====================================================================" + echo "Running test ${T} on ${TEST_RUN} ${TEST_ENDPOINT} with server ${SERVER_MODE}" + TEST_FULL_NAME="${T}-${TEST_RUN}-${SERVER_MODE}" + ${TEST_BIN_DIR}/func_otlp_http --debug --mode ${SERVER_MODE} --cert-dir ${CERT_DIR} --endpoint ${TEST_ENDPOINT} ${T} + RC=$? + if [ ${RC} -eq 0 ]; then + echo "TEST ${TEST_FULL_NAME}: PASSED" | tee -a report.log + else + echo "TEST ${TEST_FULL_NAME}: FAILED" | tee -a report.log + fi +done + diff --git a/opentracing-shim/BUILD b/opentracing-shim/BUILD new file mode 100644 index 0000000000..e7d90a4b4d --- /dev/null +++ b/opentracing-shim/BUILD @@ -0,0 +1,106 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "opentracing_shim", + srcs = [ + "src/shim_utils.cc", + "src/span_context_shim.cc", + "src/span_shim.cc", + "src/tracer_shim.cc", + ], + hdrs = [ + "include/opentelemetry/opentracingshim/propagation.h", + "include/opentelemetry/opentracingshim/shim_utils.h", + "include/opentelemetry/opentracingshim/span_context_shim.h", + "include/opentelemetry/opentracingshim/span_shim.h", + "include/opentelemetry/opentracingshim/tracer_shim.h", + ], + strip_include_prefix = "include", + tags = ["opentracing"], + deps = [ + "//api", + "@com_github_opentracing//:opentracing", + ], +) + +cc_test( + name = "propagation_test", + srcs = [ + "test/propagation_test.cc", + "test/shim_mocks.h", + ], + tags = [ + "opentracing_shim", + "test", + ], + deps = [ + ":opentracing_shim", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "shim_utils_test", + srcs = [ + "test/shim_mocks.h", + "test/shim_utils_test.cc", + ], + tags = [ + "opentracing_shim", + "test", + ], + deps = [ + ":opentracing_shim", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "span_shim_test", + srcs = [ + "test/shim_mocks.h", + "test/span_shim_test.cc", + ], + tags = [ + "opentracing_shim", + "test", + ], + deps = [ + ":opentracing_shim", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "span_context_shim_test", + srcs = [ + "test/span_context_shim_test.cc", + ], + tags = [ + "opentracing_shim", + "test", + ], + deps = [ + ":opentracing_shim", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "tracer_shim_test", + srcs = [ + "test/shim_mocks.h", + "test/tracer_shim_test.cc", + ], + tags = [ + "opentracing_shim", + "test", + ], + deps = [ + ":opentracing_shim", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/opentracing-shim/CMakeLists.txt b/opentracing-shim/CMakeLists.txt new file mode 100644 index 0000000000..3a57ac07bf --- /dev/null +++ b/opentracing-shim/CMakeLists.txt @@ -0,0 +1,63 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +set(this_target opentelemetry_opentracing_shim) + +add_library(${this_target} src/shim_utils.cc src/span_shim.cc + src/span_context_shim.cc src/tracer_shim.cc) + +set_target_properties(${this_target} PROPERTIES EXPORT_NAME opentracing_shim) + +target_include_directories( + ${this_target} PUBLIC "$" + "$") + +if(OPENTRACING_DIR) + include_directories( + "${CMAKE_BINARY_DIR}/${OPENTRACING_DIR}/include" + "${CMAKE_SOURCE_DIR}/${OPENTRACING_DIR}/include" + "${CMAKE_SOURCE_DIR}/${OPENTRACING_DIR}/3rd_party/include") + target_link_libraries(${this_target} opentelemetry_api opentracing) +else() + target_link_libraries(${this_target} opentelemetry_api + OpenTracing::opentracing) +endif() + +if(OPENTELEMETRY_INSTALL) + install( + TARGETS ${this_target} + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + install( + DIRECTORY include/opentelemetry/opentracingshim + DESTINATION include/opentelemetry + FILES_MATCHING + PATTERN "*.h") +endif() + +if(BUILD_TESTING) + foreach(testname propagation_test shim_utils_test span_shim_test + span_context_shim_test tracer_shim_test) + + add_executable(${testname} "test/${testname}.cc") + + if(OPENTRACING_DIR) + target_link_libraries( + ${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} + opentelemetry_api opentelemetry_opentracing_shim opentracing) + else() + target_link_libraries( + ${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} + opentelemetry_api opentelemetry_opentracing_shim + OpenTracing::opentracing) + endif() + + gtest_add_tests( + TARGET ${testname} + TEST_PREFIX opentracing_shim. + TEST_LIST ${testname}) + endforeach() +endif() # BUILD_TESTING diff --git a/opentracing-shim/README.md b/opentracing-shim/README.md new file mode 100644 index 0000000000..5a4fc77408 --- /dev/null +++ b/opentracing-shim/README.md @@ -0,0 +1,53 @@ +# C++ OpenTracing Shim + +[![Apache License][license-image]][license-image] + +An [OpenTracing shim][migrating] is a bridge layer from OpenTelemetry to the +OpenTracing API. It takes an OpenTelemetry Tracer and exposes it as an +implementation compatible with that of an OpenTracing Tracer. + +## Usage + +Use the TracerShim wherever you initialize your OpenTracing tracers. +There are 2 ways to expose an OpenTracing Tracer: + +1. From the global OpenTelemetry configuration: + + ```cpp + auto tracer_shim = TracerShim::createTracerShim(); + ``` + +1. From a provided OpenTelemetry Tracer instance: + + ```cpp + auto tracer_shim = TracerShim::createTracerShim(tracer); + ``` + +Optionally, one can also specify the propagators to be used for the OpenTracing `TextMap` +and `HttpHeaders` formats: + +```cpp +OpenTracingPropagators propagators{ + .text_map = nostd::shared_ptr(new CustomTextMap()), + .http_headers = nostd::shared_ptr(new trace::propagation::HttpTraceContext()) +}; + +auto tracer_shim = TracerShim::createTracerShim(tracer, propagators); +``` + +If propagators are not specified, OpenTelemetry's global propagator will be used. + +## More information and help + +- [Migrating from OpenTracing][migrating] +- [OpenTelemetry](https://opentelemetry.io) +- For help or feedback on this project, join us in [GitHub Discussions][discussions-url] + +## License + +Apache 2.0 - See [LICENSE][license-url] for more information. + +[discussions-url]: https://github.com/open-telemetry/opentelemetry-cpp/discussions +[license-url]: https://github.com/open-telemetry/opentelemetry-cpp/blob/main/LICENSE +[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat +[migrating]: https://opentelemetry.io/docs/migration/opentracing/ diff --git a/opentracing-shim/include/opentelemetry/opentracingshim/propagation.h b/opentracing-shim/include/opentelemetry/opentracingshim/propagation.h new file mode 100644 index 0000000000..c226d9da83 --- /dev/null +++ b/opentracing-shim/include/opentelemetry/opentracingshim/propagation.h @@ -0,0 +1,90 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "opentelemetry/baggage/baggage.h" +#include "opentelemetry/common/attribute_value.h" +#include "opentelemetry/context/propagation/text_map_propagator.h" +#include "opentelemetry/nostd/type_traits.h" +#include "opentracing/propagation.h" +#include "opentracing/value.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace opentracingshim +{ + +class CarrierWriterShim : public opentelemetry::context::propagation::TextMapCarrier +{ +public: + CarrierWriterShim(const opentracing::TextMapWriter &writer) : writer_(writer) {} + + virtual nostd::string_view Get(nostd::string_view) const noexcept override + { + return {}; // Not required for Opentracing writer + } + + virtual void Set(nostd::string_view key, nostd::string_view value) noexcept override + { + writer_.Set(key.data(), value.data()); + } + +private: + const opentracing::TextMapWriter &writer_; +}; + +class CarrierReaderShim : public opentelemetry::context::propagation::TextMapCarrier +{ +public: + CarrierReaderShim(const opentracing::TextMapReader &reader) : reader_(reader) {} + + virtual nostd::string_view Get(nostd::string_view key) const noexcept override + { + nostd::string_view value; + + // First try carrier.LookupKey since that can potentially be the fastest approach. + if (auto result = reader_.LookupKey(key.data())) + { + value = result.value().data(); + } + else // Fall back to iterating through all of the keys. + { + reader_.ForeachKey([key, &value](opentracing::string_view k, + opentracing::string_view v) -> opentracing::expected { + if (k == key.data()) + { + value = v.data(); + // Found key, so bail out of the loop with a success error code. + return opentracing::make_unexpected(std::error_code{}); + } + return opentracing::make_expected(); + }); + } + + return value; + } + + virtual void Set(nostd::string_view, nostd::string_view) noexcept override + { + // Not required for Opentracing reader + } + + virtual bool Keys(nostd::function_ref callback) const noexcept override + { + return reader_ + .ForeachKey([&callback](opentracing::string_view key, + opentracing::string_view) -> opentracing::expected { + return callback(key.data()) ? opentracing::make_expected() + : opentracing::make_unexpected(std::error_code{}); + }) + .has_value(); + } + +private: + const opentracing::TextMapReader &reader_; +}; + +} // namespace opentracingshim +OPENTELEMETRY_END_NAMESPACE diff --git a/opentracing-shim/include/opentelemetry/opentracingshim/shim_utils.h b/opentracing-shim/include/opentelemetry/opentracingshim/shim_utils.h new file mode 100644 index 0000000000..871bed590f --- /dev/null +++ b/opentracing-shim/include/opentelemetry/opentracingshim/shim_utils.h @@ -0,0 +1,165 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "opentelemetry/opentracingshim/span_context_shim.h" + +#include "opentelemetry/trace/semantic_conventions.h" +#include "opentelemetry/trace/tracer.h" +#include "opentracing/tracer.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace opentracingshim +{ +namespace utils +{ + +static inline opentelemetry::common::AttributeValue attributeFromValue( + const opentracing::Value &value) +{ + using opentelemetry::common::AttributeValue; + + static struct + { + AttributeValue operator()(bool v) { return v; } + AttributeValue operator()(double v) { return v; } + AttributeValue operator()(int64_t v) { return v; } + AttributeValue operator()(uint64_t v) { return v; } + AttributeValue operator()(const std::string &v) { return nostd::string_view{v}; } + AttributeValue operator()(opentracing::string_view v) { return nostd::string_view{v.data()}; } + AttributeValue operator()(std::nullptr_t) { return nostd::string_view{}; } + AttributeValue operator()(const char *v) { return v; } + AttributeValue operator()(opentracing::util::recursive_wrapper) + { + return nostd::string_view{}; + } + AttributeValue operator()(opentracing::util::recursive_wrapper) + { + return nostd::string_view{}; + } + } AttributeMapper; + + return opentracing::Value::visit(value, AttributeMapper); +} + +static inline std::string stringFromValue(const opentracing::Value &value) +{ + static struct + { + std::string operator()(bool v) { return v ? "true" : "false"; } + std::string operator()(double v) { return std::to_string(v); } + std::string operator()(int64_t v) { return std::to_string(v); } + std::string operator()(uint64_t v) { return std::to_string(v); } + std::string operator()(const std::string &v) { return v; } + std::string operator()(opentracing::string_view v) { return std::string{v.data()}; } + std::string operator()(std::nullptr_t) { return std::string{}; } + std::string operator()(const char *v) { return std::string{v}; } + std::string operator()(opentracing::util::recursive_wrapper) + { + return std::string{}; + } + std::string operator()(opentracing::util::recursive_wrapper) + { + return std::string{}; + } + } StringMapper; + + return opentracing::Value::visit(value, StringMapper); +} + +static inline bool isBaggageEmpty(const nostd::shared_ptr &baggage) +{ + if (baggage) + { + return baggage->GetAllEntries([](nostd::string_view, nostd::string_view) { return false; }); + } + + return true; +} + +class LinksIterable final : public opentelemetry::trace::SpanContextKeyValueIterable +{ +public: + using RefsList = + std::vector>; + + explicit LinksIterable(const RefsList &refs) noexcept : refs_(refs) {} + + bool ForEachKeyValue(nostd::function_ref + callback) const noexcept override + { + using opentracing::SpanReferenceType; + using namespace opentelemetry::trace::SemanticConventions; + using LinksList = std::initializer_list>; + + for (const auto &entry : refs_) + { + nostd::string_view span_kind; + + if (entry.first == SpanReferenceType::ChildOfRef) + { + span_kind = OpentracingRefTypeValues::kChildOf; + } + else if (entry.first == SpanReferenceType::FollowsFromRef) + { + span_kind = OpentracingRefTypeValues::kFollowsFrom; + } + + auto context_shim = SpanContextShim::extractFrom(entry.second); + + if (context_shim && !span_kind.empty() && + !callback(context_shim->context(), opentelemetry::common::KeyValueIterableView( + {{kOpentracingRefType, span_kind}}))) + { + return false; + } + } + + return true; + } + + size_t size() const noexcept override { return refs_.size(); } + +private: + const RefsList &refs_; +}; + +class TagsIterable final : public opentelemetry::common::KeyValueIterable +{ +public: + explicit TagsIterable( + const std::vector> &tags) noexcept + : tags_(tags) + {} + + bool ForEachKeyValue(nostd::function_ref + callback) const noexcept override + { + for (const auto &entry : tags_) + { + if (!callback(entry.first, utils::attributeFromValue(entry.second))) + return false; + } + return true; + } + + size_t size() const noexcept override { return tags_.size(); } + +private: + const std::vector> &tags_; +}; + +opentelemetry::trace::StartSpanOptions makeOptionsShim( + const opentracing::StartSpanOptions &options) noexcept; +LinksIterable makeIterableLinks(const opentracing::StartSpanOptions &options) noexcept; +TagsIterable makeIterableTags(const opentracing::StartSpanOptions &options) noexcept; +nostd::shared_ptr makeBaggage( + const opentracing::StartSpanOptions &options) noexcept; + +} // namespace utils +} // namespace opentracingshim +OPENTELEMETRY_END_NAMESPACE diff --git a/opentracing-shim/include/opentelemetry/opentracingshim/span_context_shim.h b/opentracing-shim/include/opentelemetry/opentracingshim/span_context_shim.h new file mode 100644 index 0000000000..62fec23c1a --- /dev/null +++ b/opentracing-shim/include/opentelemetry/opentracingshim/span_context_shim.h @@ -0,0 +1,66 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "opentelemetry/baggage/baggage.h" +#include "opentelemetry/trace/span_context.h" +#include "opentracing/span.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace opentracingshim +{ + +using BaggagePtr = nostd::shared_ptr; + +class SpanContextShim final : public opentracing::SpanContext +{ +public: + explicit SpanContextShim(const opentelemetry::trace::SpanContext &context, + const BaggagePtr &baggage) + : context_(context), baggage_(baggage) + {} + + inline const opentelemetry::trace::SpanContext &context() const { return context_; } + inline const BaggagePtr baggage() const { return baggage_; } + SpanContextShim newWithKeyValue(nostd::string_view key, nostd::string_view value) const noexcept; + bool BaggageItem(nostd::string_view key, std::string &value) const noexcept; + + using VisitBaggageItem = std::function; + void ForeachBaggageItem(VisitBaggageItem f) const override; + std::unique_ptr Clone() const noexcept override; + std::string ToTraceID() const noexcept override; + std::string ToSpanID() const noexcept override; + + static inline const SpanContextShim *extractFrom(const opentracing::SpanContext *span_context) + { +#ifndef OPENTELEMETRY_RTTI_ENABLED + auto result = static_cast(span_context); + return result && result->provides_context_and_baggage_ == kUniqueTag ? result : nullptr; +#else + return dynamic_cast(span_context); +#endif + } + +private: + template + static std::string toHexString(const T &id_item) + { + char buf[T::kSize * 2]; + id_item.ToLowerBase16(buf); + return std::string(buf, sizeof(buf)); + } + + opentelemetry::trace::SpanContext context_; + BaggagePtr baggage_; + +#ifndef OPENTELEMETRY_RTTI_ENABLED + static constexpr uint64_t kUniqueTag = 0x07e1ca578e57a71c; + uint64_t provides_context_and_baggage_ = kUniqueTag; +#endif +}; + +} // namespace opentracingshim +OPENTELEMETRY_END_NAMESPACE diff --git a/opentracing-shim/include/opentelemetry/opentracingshim/span_shim.h b/opentracing-shim/include/opentelemetry/opentracingshim/span_shim.h new file mode 100644 index 0000000000..4fe48852c1 --- /dev/null +++ b/opentracing-shim/include/opentelemetry/opentracingshim/span_shim.h @@ -0,0 +1,59 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "opentelemetry/opentracingshim/span_context_shim.h" +#include "opentelemetry/opentracingshim/tracer_shim.h" + +#include "opentelemetry/baggage/baggage.h" +#include "opentelemetry/common/attribute_value.h" +#include "opentelemetry/common/spin_lock_mutex.h" +#include "opentelemetry/trace/span.h" +#include "opentracing/span.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace opentracingshim +{ + +using SpanPtr = nostd::shared_ptr; +using EventEntry = std::pair; + +class SpanShim : public opentracing::Span +{ +public: + explicit SpanShim(const TracerShim &tracer, const SpanPtr &span, const BaggagePtr &baggage) + : tracer_(tracer), span_(span), context_(span->GetContext(), baggage) + {} + + void handleError(const opentracing::Value &value) noexcept; + + void FinishWithOptions( + const opentracing::FinishSpanOptions &finish_span_options) noexcept override; + void SetOperationName(opentracing::string_view name) noexcept override; + void SetTag(opentracing::string_view key, const opentracing::Value &value) noexcept override; + void SetBaggageItem(opentracing::string_view restricted_key, + opentracing::string_view value) noexcept override; + std::string BaggageItem(opentracing::string_view restricted_key) const noexcept override; + void Log(std::initializer_list fields) noexcept override; + void Log(opentracing::SystemTime timestamp, + std::initializer_list fields) noexcept override; + void Log(opentracing::SystemTime timestamp, + const std::vector &fields) noexcept override; + inline const opentracing::SpanContext &context() const noexcept override { return context_; } + inline const opentracing::Tracer &tracer() const noexcept override { return tracer_; } + +private: + void logImpl(nostd::span fields, + const opentracing::SystemTime *const timestamp) noexcept; + + const TracerShim &tracer_; + SpanPtr span_; + SpanContextShim context_; + mutable opentelemetry::common::SpinLockMutex context_lock_; +}; + +} // namespace opentracingshim +OPENTELEMETRY_END_NAMESPACE diff --git a/opentracing-shim/include/opentelemetry/opentracingshim/tracer_shim.h b/opentracing-shim/include/opentelemetry/opentracingshim/tracer_shim.h new file mode 100644 index 0000000000..7f2d492efd --- /dev/null +++ b/opentracing-shim/include/opentelemetry/opentracingshim/tracer_shim.h @@ -0,0 +1,80 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "opentelemetry/context/propagation/text_map_propagator.h" +#include "opentelemetry/trace/provider.h" +#include "opentelemetry/trace/tracer.h" +#include "opentracing/tracer.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace opentracingshim +{ + +using TracerPtr = nostd::shared_ptr; +using TracerProviderPtr = nostd::shared_ptr; +using PropagatorPtr = nostd::shared_ptr; + +struct OpenTracingPropagators +{ + PropagatorPtr text_map; + PropagatorPtr http_headers; +}; + +class TracerShim : public opentracing::Tracer +{ +public: + static inline std::shared_ptr createTracerShim( + const TracerProviderPtr &provider = opentelemetry::trace::Provider::GetTracerProvider(), + const OpenTracingPropagators &propagators = {}) noexcept + { + // This operation MUST accept the following parameters: + // - An OpenTelemetry TracerProvider. This operation MUST use this TracerProvider to obtain a + // Tracer with the name opentracing-shim along with the current shim library version. + // - OpenTelemetry Propagators to be used to perform injection and extraction for the + // OpenTracing TextMap and HTTPHeaders formats. If not specified, no Propagator values will + // be stored in the Shim, and the global OpenTelemetry TextMap propagator will be used for + // both OpenTracing TextMap and HTTPHeaders formats. + return std::shared_ptr( + new (std::nothrow) TracerShim(provider->GetTracer("opentracing-shim"), propagators)); + } + + std::unique_ptr StartSpanWithOptions( + opentracing::string_view operation_name, + const opentracing::StartSpanOptions &options) const noexcept override; + opentracing::expected Inject(const opentracing::SpanContext &sc, + std::ostream &writer) const override; + opentracing::expected Inject(const opentracing::SpanContext &sc, + const opentracing::TextMapWriter &writer) const override; + opentracing::expected Inject(const opentracing::SpanContext &sc, + const opentracing::HTTPHeadersWriter &writer) const override; + opentracing::expected> Extract( + std::istream &reader) const override; + opentracing::expected> Extract( + const opentracing::TextMapReader &reader) const override; + opentracing::expected> Extract( + const opentracing::HTTPHeadersReader &reader) const override; + inline void Close() noexcept override { is_closed_ = true; } + +private: + explicit TracerShim(const TracerPtr &tracer, const OpenTracingPropagators &propagators) + : tracer_(tracer), propagators_(propagators) + {} + + opentracing::expected injectImpl(const opentracing::SpanContext &sc, + const opentracing::TextMapWriter &writer, + const PropagatorPtr &propagator) const; + opentracing::expected> extractImpl( + const opentracing::TextMapReader &reader, + const PropagatorPtr &propagator) const; + + TracerPtr tracer_; + OpenTracingPropagators propagators_; + bool is_closed_ = false; +}; + +} // namespace opentracingshim +OPENTELEMETRY_END_NAMESPACE diff --git a/opentracing-shim/src/shim_utils.cc b/opentracing-shim/src/shim_utils.cc new file mode 100644 index 0000000000..8829eafdf3 --- /dev/null +++ b/opentracing-shim/src/shim_utils.cc @@ -0,0 +1,89 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "opentelemetry/opentracingshim/shim_utils.h" + +#include "opentelemetry/baggage/baggage_context.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace opentracingshim +{ +namespace utils +{ + +opentelemetry::trace::StartSpanOptions makeOptionsShim( + const opentracing::StartSpanOptions &options) noexcept +{ + using opentracing::SpanReferenceType; + // If an explicit start timestamp is specified, a conversion MUST + // be done to match the OpenTracing and OpenTelemetry units. + opentelemetry::trace::StartSpanOptions options_shim; + options_shim.start_system_time = + opentelemetry::common::SystemTimestamp{options.start_system_timestamp}; + options_shim.start_steady_time = + opentelemetry::common::SteadyTimestamp{options.start_steady_timestamp}; + + const auto &refs = options.references; + // If a list of Span references is specified... + if (!refs.empty()) + { + const auto &first_child_of = std::find_if( + refs.cbegin(), refs.cend(), + [](const std::pair &entry) { + return entry.first == SpanReferenceType::ChildOfRef; + }); + // The first SpanContext with Child Of type in the entire list is used as parent, + // else the first SpanContext is used as parent + auto context = (first_child_of != refs.cend()) ? first_child_of->second : refs.cbegin()->second; + + if (auto context_shim = SpanContextShim::extractFrom(context)) + { + options_shim.parent = context_shim->context(); + } + } + + return options_shim; +} + +LinksIterable makeIterableLinks(const opentracing::StartSpanOptions &options) noexcept +{ + return LinksIterable(options.references); +} + +TagsIterable makeIterableTags(const opentracing::StartSpanOptions &options) noexcept +{ + return TagsIterable(options.tags); +} + +nostd::shared_ptr makeBaggage( + const opentracing::StartSpanOptions &options) noexcept +{ + using namespace opentelemetry::baggage; + + std::unordered_map baggage_items; + // If a list of Span references is specified... + for (const auto &entry : options.references) + { + // The union of their Baggage values MUST be used + // as the initial Baggage of the newly created Span. + entry.second->ForeachBaggageItem( + [&baggage_items](const std::string &key, const std::string &value) { + // It is unspecified which Baggage value is used in the case of repeated keys. + if (baggage_items.find(key) == baggage_items.end()) + { + baggage_items.emplace(key, value); // Here, only insert if key not already present + } + return true; + }); + } + // If no such list of references is specified, the current Baggage + // MUST be used as the initial value of the newly created Span. + return baggage_items.empty() ? GetBaggage(opentelemetry::context::RuntimeContext::GetCurrent()) + : nostd::shared_ptr(new Baggage(baggage_items)); +} + +} // namespace utils +} // namespace opentracingshim +OPENTELEMETRY_END_NAMESPACE diff --git a/opentracing-shim/src/span_context_shim.cc b/opentracing-shim/src/span_context_shim.cc new file mode 100644 index 0000000000..54af4da9a3 --- /dev/null +++ b/opentracing-shim/src/span_context_shim.cc @@ -0,0 +1,46 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "opentelemetry/opentracingshim/span_context_shim.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace opentracingshim +{ + +SpanContextShim SpanContextShim::newWithKeyValue(nostd::string_view key, + nostd::string_view value) const noexcept +{ + return SpanContextShim{context_, baggage_->Set(key, value)}; +} + +bool SpanContextShim::BaggageItem(nostd::string_view key, std::string &value) const noexcept +{ + return baggage_->GetValue(key, value); +} + +void SpanContextShim::ForeachBaggageItem(VisitBaggageItem f) const +{ + baggage_->GetAllEntries([&f](nostd::string_view key, nostd::string_view value) { + return f(key.data(), value.data()); + }); +} + +std::unique_ptr SpanContextShim::Clone() const noexcept +{ + return std::unique_ptr(new (std::nothrow) SpanContextShim(context_, baggage_)); +} + +std::string SpanContextShim::ToTraceID() const noexcept +{ + return toHexString(context_.trace_id()); +} + +std::string SpanContextShim::ToSpanID() const noexcept +{ + return toHexString(context_.span_id()); +} + +} // namespace opentracingshim +OPENTELEMETRY_END_NAMESPACE diff --git a/opentracing-shim/src/span_shim.cc b/opentracing-shim/src/span_shim.cc new file mode 100644 index 0000000000..808b6b9e74 --- /dev/null +++ b/opentracing-shim/src/span_shim.cc @@ -0,0 +1,164 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "opentelemetry/opentracingshim/span_shim.h" +#include "opentelemetry/opentracingshim/shim_utils.h" +#include "opentelemetry/opentracingshim/span_context_shim.h" +#include "opentelemetry/opentracingshim/tracer_shim.h" + +#include "opentelemetry/trace/semantic_conventions.h" +#include "opentelemetry/trace/span_metadata.h" +#include "opentracing/ext/tags.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace opentracingshim +{ + +void SpanShim::handleError(const opentracing::Value &value) noexcept +{ + using opentelemetry::trace::StatusCode; + // The error tag MUST be mapped to StatusCode: + const auto &error_tag = utils::stringFromValue(value); + // - no value being set maps to Unset. + auto code = StatusCode::kUnset; + + if (error_tag == "true") // - true maps to Error. + { + code = StatusCode::kError; + } + else if (error_tag == "false") // - false maps to Ok. + { + code = StatusCode::kOk; + } + + span_->SetStatus(code); +} + +void SpanShim::FinishWithOptions(const opentracing::FinishSpanOptions &finish_span_options) noexcept +{ + // If an explicit timestamp is specified, a conversion MUST + // be done to match the OpenTracing and OpenTelemetry units. + span_->End({{finish_span_options.finish_steady_timestamp}}); +} + +void SpanShim::SetOperationName(opentracing::string_view name) noexcept +{ + span_->UpdateName(name.data()); +} + +void SpanShim::SetTag(opentracing::string_view key, const opentracing::Value &value) noexcept +{ + // Calls Set Attribute on the underlying OpenTelemetry Span with the specified key/value pair. + if (key == opentracing::ext::error) + { + handleError(value); + } + else + { + span_->SetAttribute(key.data(), utils::attributeFromValue(value)); + } +} + +void SpanShim::SetBaggageItem(opentracing::string_view restricted_key, + opentracing::string_view value) noexcept +{ + // Creates a new SpanContext Shim with a new OpenTelemetry Baggage containing the specified + // Baggage key/value pair, and sets it as the current instance for this Span Shim. + if (restricted_key.empty() || value.empty()) + return; + // This operation MUST be safe to be called concurrently. + const std::lock_guard guard(context_lock_); + context_ = context_.newWithKeyValue(restricted_key.data(), value.data()); +} + +std::string SpanShim::BaggageItem(opentracing::string_view restricted_key) const noexcept +{ + // Returns the value for the specified key in the OpenTelemetry Baggage + // of the current SpanContext Shim, or null if none exists. + if (restricted_key.empty()) + return ""; + // This operation MUST be safe to be called concurrently. + const std::lock_guard guard(context_lock_); + std::string value; + return context_.BaggageItem(restricted_key.data(), value) ? value : ""; +} + +void SpanShim::Log(std::initializer_list fields) noexcept +{ + // If an explicit timestamp is specified, a conversion MUST + // be done to match the OpenTracing and OpenTelemetry units. + logImpl(fields, nullptr); +} + +void SpanShim::Log(opentracing::SystemTime timestamp, + std::initializer_list fields) noexcept +{ + // If an explicit timestamp is specified, a conversion MUST + // be done to match the OpenTracing and OpenTelemetry units. + logImpl(fields, ×tamp); +} + +void SpanShim::Log(opentracing::SystemTime timestamp, + const std::vector &fields) noexcept +{ + // If an explicit timestamp is specified, a conversion MUST + // be done to match the OpenTracing and OpenTelemetry units. + logImpl(fields, ×tamp); +} + +void SpanShim::logImpl(nostd::span fields, + const opentracing::SystemTime *const timestamp) noexcept +{ + // The Add Event’s name parameter MUST be the value with the event key + // in the pair set, or else fallback to use the log literal string. + const auto &event = std::find_if(fields.begin(), fields.end(), + [](const EventEntry &item) { return item.first == "event"; }); + auto name = (event != fields.end()) ? utils::stringFromValue(event->second) : std::string{"log"}; + // If pair set contains an event=error entry, the values MUST be mapped to an Event + // with the conventions outlined in the Exception semantic conventions document: + bool is_error = (name == opentracing::ext::error); + // A call to AddEvent is performed with name being set to exception + if (is_error) + name = "exception"; + // Along the specified key/value pair set as additional event attributes... + std::vector> attributes; + attributes.reserve(fields.size()); + + for (const auto &entry : fields) + { + nostd::string_view key = entry.first.data(); + // ... including mapping of the following key/value pairs: + if (is_error) + { + if (key == "error.kind") // - error.kind maps to exception.type. + { + key = opentelemetry::trace::SemanticConventions::kExceptionType; + } + else if (key == "message") // - message maps to exception.message. + { + key = opentelemetry::trace::SemanticConventions::kExceptionMessage; + } + else if (key == "stack") // - stack maps to exception.stacktrace. + { + key = opentelemetry::trace::SemanticConventions::kExceptionStacktrace; + } + } + + attributes.emplace_back(key, utils::attributeFromValue(entry.second)); + } + + // Calls Add Events on the underlying OpenTelemetry Span with the specified key/value pair set. + if (timestamp) + { + span_->AddEvent(name, *timestamp, attributes); + } + else + { + span_->AddEvent(name, attributes); + } +} + +} // namespace opentracingshim +OPENTELEMETRY_END_NAMESPACE diff --git a/opentracing-shim/src/tracer_shim.cc b/opentracing-shim/src/tracer_shim.cc new file mode 100644 index 0000000000..c8805d15ef --- /dev/null +++ b/opentracing-shim/src/tracer_shim.cc @@ -0,0 +1,162 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "opentelemetry/opentracingshim/tracer_shim.h" +#include "opentelemetry/opentracingshim/propagation.h" +#include "opentelemetry/opentracingshim/shim_utils.h" +#include "opentelemetry/opentracingshim/span_shim.h" + +#include "opentelemetry/baggage/baggage_context.h" +#include "opentelemetry/context/propagation/global_propagator.h" +#include "opentelemetry/trace/context.h" +#include "opentracing/ext/tags.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace opentracingshim +{ + +std::unique_ptr TracerShim::StartSpanWithOptions( + opentracing::string_view operation_name, + const opentracing::StartSpanOptions &options) const noexcept +{ + if (is_closed_) + return nullptr; + + const auto &opts = utils::makeOptionsShim(options); + const auto &links = utils::makeIterableLinks(options); + const auto &attributes = utils::makeIterableTags(options); + const auto &baggage = utils::makeBaggage(options); + auto span = tracer_->StartSpan(operation_name.data(), attributes, links, opts); + auto span_shim = new (std::nothrow) SpanShim(*this, span, baggage); + + // If an initial set of tags is specified and the OpenTracing error tag + // is included after the OpenTelemetry Span was created. + const auto &error_entry = + std::find_if(options.tags.cbegin(), options.tags.cend(), + [](const std::pair &entry) { + return entry.first == opentracing::ext::error; + }); + // The Shim layer MUST perform the same error handling as described in the Set Tag operation + if (span_shim && error_entry != options.tags.cend()) + { + span_shim->handleError(error_entry->second); + } + + return std::unique_ptr(span_shim); +} + +opentracing::expected TracerShim::Inject(const opentracing::SpanContext &, + std::ostream &) const +{ + // Errors MAY be raised if the specified Format is not recognized, + // depending on the specific OpenTracing Language API. + return opentracing::make_unexpected(opentracing::invalid_carrier_error); +} + +opentracing::expected TracerShim::Inject(const opentracing::SpanContext &sc, + const opentracing::TextMapWriter &writer) const +{ + // TextMap and HttpHeaders formats MUST use their explicitly specified TextMapPropagator, + // if any, or else use the global TextMapPropagator. + const auto &propagator = + propagators_.text_map + ? propagators_.text_map + : opentelemetry::context::propagation::GlobalTextMapPropagator::GetGlobalPropagator(); + + return injectImpl(sc, writer, propagator); +} + +opentracing::expected TracerShim::Inject(const opentracing::SpanContext &sc, + const opentracing::HTTPHeadersWriter &writer) const +{ + // TextMap and HttpHeaders formats MUST use their explicitly specified TextMapPropagator, + // if any, or else use the global TextMapPropagator. + const auto &propagator = + propagators_.http_headers + ? propagators_.http_headers + : opentelemetry::context::propagation::GlobalTextMapPropagator::GetGlobalPropagator(); + + return injectImpl(sc, writer, propagator); +} + +opentracing::expected> TracerShim::Extract( + std::istream &) const +{ + // Errors MAY be raised if either the Format is not recognized or no value + // could be extracted, depending on the specific OpenTracing Language API. + return opentracing::make_unexpected(opentracing::invalid_carrier_error); +} + +opentracing::expected> TracerShim::Extract( + const opentracing::TextMapReader &reader) const +{ + // TextMap and HttpHeaders formats MUST use their explicitly specified TextMapPropagator, + // if any, or else use the global TextMapPropagator. + const auto &propagator = + propagators_.text_map + ? propagators_.text_map + : opentelemetry::context::propagation::GlobalTextMapPropagator::GetGlobalPropagator(); + + return extractImpl(reader, propagator); +} + +opentracing::expected> TracerShim::Extract( + const opentracing::HTTPHeadersReader &reader) const +{ + // TextMap and HttpHeaders formats MUST use their explicitly specified TextMapPropagator, + // if any, or else use the global TextMapPropagator. + const auto &propagator = + propagators_.http_headers + ? propagators_.http_headers + : opentelemetry::context::propagation::GlobalTextMapPropagator::GetGlobalPropagator(); + + return extractImpl(reader, propagator); +} + +opentracing::expected TracerShim::injectImpl(const opentracing::SpanContext &sc, + const opentracing::TextMapWriter &writer, + const PropagatorPtr &propagator) const +{ + // Inject the underlying OpenTelemetry Span and Baggage using either the explicitly registered + // or the global OpenTelemetry Propagators, as configured at construction time. + if (auto context_shim = SpanContextShim::extractFrom(&sc)) + { + auto current_context = opentelemetry::context::RuntimeContext::GetCurrent(); + // It MUST inject any non-empty Baggage even amidst no valid SpanContext. + const auto &context = + opentelemetry::baggage::SetBaggage(current_context, context_shim->baggage()); + + CarrierWriterShim carrier{writer}; + propagator->Inject(carrier, context); + return opentracing::make_expected(); + } + + return opentracing::make_unexpected(opentracing::invalid_span_context_error); +} + +opentracing::expected> TracerShim::extractImpl( + const opentracing::TextMapReader &reader, + const PropagatorPtr &propagator) const +{ + // Extract the underlying OpenTelemetry Span and Baggage using either the explicitly registered + // or the global OpenTelemetry Propagators, as configured at construction time. + CarrierReaderShim carrier{reader}; + auto current_context = opentelemetry::context::RuntimeContext::GetCurrent(); + auto context = propagator->Extract(carrier, current_context); + auto span_context = opentelemetry::trace::GetSpan(context)->GetContext(); + auto baggage = opentelemetry::baggage::GetBaggage(context); + + // If the extracted SpanContext is invalid AND the extracted Baggage is empty, + // this operation MUST return a null value, and otherwise it MUST return a + // SpanContext Shim instance with the extracted values. + SpanContextShim *context_shim = (!span_context.IsValid() && utils::isBaggageEmpty(baggage)) + ? nullptr + : new (std::nothrow) SpanContextShim(span_context, baggage); + + return opentracing::make_expected(std::unique_ptr(context_shim)); +} + +} // namespace opentracingshim +OPENTELEMETRY_END_NAMESPACE diff --git a/opentracing-shim/test/propagation_test.cc b/opentracing-shim/test/propagation_test.cc new file mode 100644 index 0000000000..eb59630405 --- /dev/null +++ b/opentracing-shim/test/propagation_test.cc @@ -0,0 +1,106 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "shim_mocks.h" + +#include "opentelemetry/opentracingshim/propagation.h" + +#include + +namespace baggage = opentelemetry::baggage; +namespace common = opentelemetry::common; +namespace nostd = opentelemetry::nostd; +namespace shim = opentelemetry::opentracingshim; + +TEST(PropagationTest, TextMapReader_Get_LookupKey_Unsupported) +{ + std::unordered_map text_map; + TextMapCarrier testee{text_map}; + ASSERT_FALSE(testee.supports_lookup); + ASSERT_EQ(testee.foreach_key_call_count, 0); + + shim::CarrierReaderShim tester{testee}; + auto lookup_unsupported = testee.LookupKey("foo"); + ASSERT_TRUE(text_map.empty()); + ASSERT_TRUE(opentracing::are_errors_equal(lookup_unsupported.error(), + opentracing::lookup_key_not_supported_error)); + ASSERT_EQ(tester.Get("foo"), nostd::string_view{}); + ASSERT_EQ(testee.foreach_key_call_count, 1); + + text_map["foo"] = "bar"; + auto lookup_still_unsupported = testee.LookupKey("foo"); + ASSERT_FALSE(text_map.empty()); + ASSERT_TRUE(opentracing::are_errors_equal(lookup_still_unsupported.error(), + opentracing::lookup_key_not_supported_error)); + ASSERT_EQ(tester.Get("foo"), nostd::string_view{"bar"}); + ASSERT_EQ(testee.foreach_key_call_count, 2); +} + +TEST(PropagationTest, TextMapReader_Get_LookupKey_Supported) +{ + std::unordered_map text_map; + TextMapCarrier testee{text_map}; + testee.supports_lookup = true; + ASSERT_TRUE(testee.supports_lookup); + ASSERT_EQ(testee.foreach_key_call_count, 0); + + shim::CarrierReaderShim tester{testee}; + auto lookup_not_found = testee.LookupKey("foo"); + ASSERT_TRUE(text_map.empty()); + ASSERT_TRUE( + opentracing::are_errors_equal(lookup_not_found.error(), opentracing::key_not_found_error)); + ASSERT_EQ(tester.Get("foo"), nostd::string_view{}); + ASSERT_EQ(testee.foreach_key_call_count, 1); + + text_map["foo"] = "bar"; + auto lookup_found = testee.LookupKey("foo"); + ASSERT_FALSE(text_map.empty()); + ASSERT_EQ(lookup_found.value(), opentracing::string_view{"bar"}); + ASSERT_EQ(tester.Get("foo"), nostd::string_view{"bar"}); + ASSERT_EQ(testee.foreach_key_call_count, 1); +} + +TEST(PropagationTest, TextMapReader_Keys) +{ + std::unordered_map text_map; + TextMapCarrier testee{text_map}; + ASSERT_EQ(testee.foreach_key_call_count, 0); + + shim::CarrierReaderShim tester{testee}; + std::vector kvs; + auto callback = [&text_map, &kvs](nostd::string_view k) { + kvs.emplace_back(k); + return !text_map.empty(); + }; + + ASSERT_TRUE(tester.Keys(callback)); + ASSERT_TRUE(text_map.empty()); + ASSERT_TRUE(kvs.empty()); + ASSERT_EQ(testee.foreach_key_call_count, 1); + + text_map["foo"] = "bar"; + text_map["bar"] = "baz"; + text_map["baz"] = "foo"; + ASSERT_TRUE(tester.Keys(callback)); + ASSERT_FALSE(text_map.empty()); + ASSERT_EQ(text_map.size(), kvs.size()); + ASSERT_EQ(testee.foreach_key_call_count, 2); +} + +TEST(PropagationTest, TextMapWriter_Set) +{ + std::unordered_map text_map; + TextMapCarrier testee{text_map}; + shim::CarrierWriterShim tester{testee}; + ASSERT_TRUE(text_map.empty()); + + tester.Set("foo", "bar"); + tester.Set("bar", "baz"); + tester.Set("baz", "foo"); + ASSERT_EQ(text_map.size(), 3); + ASSERT_EQ(text_map["foo"], "bar"); + ASSERT_EQ(text_map["bar"], "baz"); + ASSERT_EQ(text_map["baz"], "foo"); +} diff --git a/opentracing-shim/test/shim_mocks.h b/opentracing-shim/test/shim_mocks.h new file mode 100644 index 0000000000..555f6cb65b --- /dev/null +++ b/opentracing-shim/test/shim_mocks.h @@ -0,0 +1,230 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "opentelemetry/baggage/baggage_context.h" +#include "opentelemetry/context/propagation/text_map_propagator.h" +#include "opentelemetry/trace/span.h" +#include "opentelemetry/trace/span_context.h" +#include "opentelemetry/trace/span_metadata.h" +#include "opentelemetry/trace/tracer.h" +#include "opentelemetry/trace/tracer_provider.h" +#include "opentracing/propagation.h" + +#include +#include + +namespace trace_api = opentelemetry::trace; +namespace baggage = opentelemetry::baggage; +namespace common = opentelemetry::common; +namespace context = opentelemetry::context; +namespace nostd = opentelemetry::nostd; + +struct MockSpan final : public trace_api::Span +{ + void SetAttribute(nostd::string_view key, const common::AttributeValue &value) noexcept override + { + attribute_ = {key.data(), value}; + } + + void AddEvent(nostd::string_view name, + common::SystemTimestamp timestamp, + const common::KeyValueIterable &attributes) noexcept override + { + std::unordered_map attribute_map; + attribute_map.reserve(attributes.size()); + attributes.ForEachKeyValue( + [&attribute_map](nostd::string_view key, const common::AttributeValue &value) { + attribute_map.emplace(key.data(), value); + return true; + }); + event_ = {name.data(), timestamp, attribute_map}; + } + + void AddEvent(nostd::string_view name, + const common::KeyValueIterable &attributes) noexcept override + { + AddEvent(name, {}, attributes); + } + + void AddEvent(nostd::string_view, common::SystemTimestamp) noexcept override {} + + void AddEvent(nostd::string_view) noexcept override {} + + void SetStatus(trace_api::StatusCode code, nostd::string_view description) noexcept override + { + status_ = {code, description.data()}; + } + + void UpdateName(nostd::string_view name) noexcept override { name_ = name.data(); } + + void End(const trace_api::EndSpanOptions &options) noexcept override { options_ = options; } + + bool IsRecording() const noexcept override { return false; } + + trace_api::SpanContext GetContext() const noexcept override + { + return trace_api::SpanContext(false, false); + } + + std::pair attribute_; + std::tuple> + event_; + std::pair status_; + std::string name_; + trace_api::EndSpanOptions options_; +}; + +struct MockTracer final : public trace_api::Tracer +{ + nostd::shared_ptr StartSpan( + nostd::string_view name, + const common::KeyValueIterable &, + const trace_api::SpanContextKeyValueIterable &, + const trace_api::StartSpanOptions &) noexcept override + { + span_ = new MockSpan(); + span_->name_ = std::string{name}; + return nostd::shared_ptr(span_); + } + + void ForceFlushWithMicroseconds(uint64_t) noexcept override {} + + void CloseWithMicroseconds(uint64_t) noexcept override {} + + MockSpan *span_; +}; + +struct MockTracerProvider final : public trace_api::TracerProvider +{ + nostd::shared_ptr GetTracer(nostd::string_view library_name, + nostd::string_view, + nostd::string_view) noexcept override + { + library_name_ = std::string{library_name}; + tracer_ = new MockTracer(); + return nostd::shared_ptr(tracer_); + } + + std::string library_name_; + MockTracer *tracer_; +}; + +struct MockPropagator : public context::propagation::TextMapPropagator +{ + // Returns the context that is stored in the carrier with the TextMapCarrier as extractor. + context::Context Extract(const context::propagation::TextMapCarrier &carrier, + context::Context &context) noexcept override + { + std::vector> kvs; + carrier.Keys([&carrier, &kvs](nostd::string_view k) { + kvs.emplace_back(k, carrier.Get(k)); + return true; + }); + is_extracted = true; + return baggage::SetBaggage(context, + nostd::shared_ptr(new baggage::Baggage(kvs))); + } + + // Sets the context for carrier with self defined rules. + void Inject(context::propagation::TextMapCarrier &carrier, + const context::Context &context) noexcept override + { + auto baggage = baggage::GetBaggage(context); + baggage->GetAllEntries([&carrier](nostd::string_view k, nostd::string_view v) { + carrier.Set(k, v); + return true; + }); + is_injected = true; + } + + // Gets the fields set in the carrier by the `inject` method + bool Fields(nostd::function_ref) const noexcept override + { + return true; + } + + bool is_extracted = false; + bool is_injected = false; +}; + +struct TextMapCarrier : opentracing::TextMapReader, opentracing::TextMapWriter +{ + TextMapCarrier(std::unordered_map &text_map_) : text_map(text_map_) {} + + opentracing::expected Set(opentracing::string_view key, + opentracing::string_view value) const override + { + text_map[key] = value; + return {}; + } + + opentracing::expected LookupKey( + opentracing::string_view key) const override + { + if (!supports_lookup) + { + return opentracing::make_unexpected(opentracing::lookup_key_not_supported_error); + } + auto iter = text_map.find(key); + if (iter != text_map.end()) + { + return opentracing::string_view{iter->second}; + } + else + { + return opentracing::make_unexpected(opentracing::key_not_found_error); + } + } + + opentracing::expected ForeachKey( + std::function(opentracing::string_view key, + opentracing::string_view value)> f) const override + { + ++foreach_key_call_count; + for (const auto &key_value : text_map) + { + auto result = f(key_value.first, key_value.second); + if (!result) + return result; + } + return {}; + } + + bool supports_lookup = false; + mutable int foreach_key_call_count = 0; + std::unordered_map &text_map; +}; + +struct HTTPHeadersCarrier : opentracing::HTTPHeadersReader, opentracing::HTTPHeadersWriter +{ + HTTPHeadersCarrier(std::unordered_map &text_map_) : text_map(text_map_) + {} + + opentracing::expected Set(opentracing::string_view key, + opentracing::string_view value) const override + { + text_map[key] = value; + return {}; + } + + opentracing::expected ForeachKey( + std::function(opentracing::string_view key, + opentracing::string_view value)> f) const override + { + for (const auto &key_value : text_map) + { + auto result = f(key_value.first, key_value.second); + if (!result) + return result; + } + return {}; + } + + std::unordered_map &text_map; +}; diff --git a/opentracing-shim/test/shim_utils_test.cc b/opentracing-shim/test/shim_utils_test.cc new file mode 100644 index 0000000000..aa2316f2d2 --- /dev/null +++ b/opentracing-shim/test/shim_utils_test.cc @@ -0,0 +1,281 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "shim_mocks.h" + +#include "opentelemetry/opentracingshim/shim_utils.h" + +#include "opentracing/tracer.h" + +#include + +namespace trace_api = opentelemetry::trace; +namespace baggage = opentelemetry::baggage; +namespace common = opentelemetry::common; +namespace nostd = opentelemetry::nostd; +namespace shim = opentelemetry::opentracingshim; + +TEST(ShimUtilsTest, IsBaggageEmpty) +{ + auto none = nostd::shared_ptr(nullptr); + ASSERT_TRUE(shim::utils::isBaggageEmpty(none)); + + auto empty = nostd::shared_ptr(new baggage::Baggage({})); + ASSERT_TRUE(shim::utils::isBaggageEmpty(empty)); + + std::map list{{"foo", "bar"}}; + auto non_empty = nostd::shared_ptr(new baggage::Baggage(list)); + ASSERT_FALSE(shim::utils::isBaggageEmpty(non_empty)); +} + +TEST(ShimUtilsTest, StringFromValue) +{ + ASSERT_EQ(shim::utils::stringFromValue(true), "true"); + ASSERT_EQ(shim::utils::stringFromValue(false), "false"); + ASSERT_EQ(shim::utils::stringFromValue(1234.567890), "1234.567890"); + ASSERT_EQ(shim::utils::stringFromValue(42l), "42"); + ASSERT_EQ(shim::utils::stringFromValue(55ul), "55"); + ASSERT_EQ(shim::utils::stringFromValue(std::string{"a string"}), "a string"); + ASSERT_EQ(shim::utils::stringFromValue(opentracing::string_view{"a string view"}), + "a string view"); + ASSERT_EQ(shim::utils::stringFromValue(nullptr), ""); + ASSERT_EQ(shim::utils::stringFromValue("a char ptr"), "a char ptr"); + + opentracing::util::recursive_wrapper values{}; + ASSERT_EQ(shim::utils::stringFromValue(values.get()), ""); + + opentracing::util::recursive_wrapper dict{}; + ASSERT_EQ(shim::utils::stringFromValue(dict.get()), ""); +} + +TEST(ShimUtilsTest, AttributeFromValue) +{ + auto value = shim::utils::attributeFromValue(true); + ASSERT_EQ(value.index(), common::AttributeType::kTypeBool); + ASSERT_TRUE(nostd::get(value)); + + value = shim::utils::attributeFromValue(false); + ASSERT_EQ(value.index(), common::AttributeType::kTypeBool); + ASSERT_FALSE(nostd::get(value)); + + value = shim::utils::attributeFromValue(1234.567890); + ASSERT_EQ(value.index(), common::AttributeType::kTypeDouble); + ASSERT_EQ(nostd::get(value), 1234.567890); + + value = shim::utils::attributeFromValue(42l); + ASSERT_EQ(value.index(), common::AttributeType::kTypeInt64); + ASSERT_EQ(nostd::get(value), 42l); + + value = shim::utils::attributeFromValue(55ul); + ASSERT_EQ(value.index(), common::AttributeType::kTypeUInt64); + ASSERT_EQ(nostd::get(value), 55ul); + + opentracing::Value str{std::string{"a string"}}; + value = shim::utils::attributeFromValue(str); + ASSERT_EQ(value.index(), common::AttributeType::kTypeString); + ASSERT_EQ(nostd::get(value), nostd::string_view{"a string"}); + + value = shim::utils::attributeFromValue(opentracing::string_view{"a string view"}); + ASSERT_EQ(value.index(), common::AttributeType::kTypeString); + ASSERT_EQ(nostd::get(value), nostd::string_view{"a string view"}); + + value = shim::utils::attributeFromValue(nullptr); + ASSERT_EQ(value.index(), common::AttributeType::kTypeString); + ASSERT_EQ(nostd::get(value), nostd::string_view{}); + + value = shim::utils::attributeFromValue("a char ptr"); + ASSERT_EQ(value.index(), common::AttributeType::kTypeCString); + ASSERT_EQ(nostd::get(value), "a char ptr"); + + opentracing::util::recursive_wrapper values{}; + value = shim::utils::attributeFromValue(values.get()); + ASSERT_EQ(value.index(), common::AttributeType::kTypeString); + ASSERT_EQ(nostd::get(value), nostd::string_view{}); + + opentracing::util::recursive_wrapper dict{}; + value = shim::utils::attributeFromValue(dict.get()); + ASSERT_EQ(value.index(), common::AttributeType::kTypeString); + ASSERT_EQ(nostd::get(value), nostd::string_view{}); +} + +TEST(ShimUtilsTest, MakeOptionsShim_EmptyRefs) +{ + opentracing::StartSpanOptions options; + options.start_system_timestamp = opentracing::SystemTime::time_point::clock::now(); + options.start_steady_timestamp = opentracing::SteadyTime::time_point::clock::now(); + + auto options_shim = shim::utils::makeOptionsShim(options); + ASSERT_EQ(options_shim.start_system_time, + common::SystemTimestamp{options.start_system_timestamp}); + ASSERT_EQ(options_shim.start_steady_time, + common::SteadyTimestamp{options.start_steady_timestamp}); + ASSERT_EQ(nostd::get(options_shim.parent), + trace_api::SpanContext::GetInvalid()); +} + +TEST(ShimUtilsTest, MakeOptionsShim_InvalidSpanContext) +{ + opentracing::StartSpanOptions options; + options.start_system_timestamp = opentracing::SystemTime::time_point::clock::now(); + options.start_steady_timestamp = opentracing::SteadyTime::time_point::clock::now(); + options.references = {{opentracing::SpanReferenceType::FollowsFromRef, nullptr}}; + + auto options_shim = shim::utils::makeOptionsShim(options); + ASSERT_EQ(options_shim.start_system_time, + common::SystemTimestamp{options.start_system_timestamp}); + ASSERT_EQ(options_shim.start_steady_time, + common::SteadyTimestamp{options.start_steady_timestamp}); + ASSERT_EQ(nostd::get(options_shim.parent), + trace_api::SpanContext::GetInvalid()); +} + +TEST(ShimUtilsTest, MakeOptionsShim_FirstChildOf) +{ + auto span_context_shim = nostd::shared_ptr(new shim::SpanContextShim( + trace_api::SpanContext::GetInvalid(), baggage::Baggage::GetDefault())); + auto span_context = static_cast(span_context_shim.get()); + + opentracing::StartSpanOptions options; + options.start_system_timestamp = opentracing::SystemTime::time_point::clock::now(); + options.start_steady_timestamp = opentracing::SteadyTime::time_point::clock::now(); + options.references = {{opentracing::SpanReferenceType::FollowsFromRef, nullptr}, + {opentracing::SpanReferenceType::ChildOfRef, span_context}, + {opentracing::SpanReferenceType::ChildOfRef, nullptr}}; + + auto options_shim = shim::utils::makeOptionsShim(options); + ASSERT_EQ(options_shim.start_system_time, + common::SystemTimestamp{options.start_system_timestamp}); + ASSERT_EQ(options_shim.start_steady_time, + common::SteadyTimestamp{options.start_steady_timestamp}); + ASSERT_EQ(nostd::get(options_shim.parent), span_context_shim->context()); +} + +TEST(ShimUtilsTest, MakeOptionsShim_FirstInList) +{ + auto span_context_shim = nostd::shared_ptr(new shim::SpanContextShim( + trace_api::SpanContext::GetInvalid(), baggage::Baggage::GetDefault())); + auto span_context = static_cast(span_context_shim.get()); + + opentracing::StartSpanOptions options; + options.start_system_timestamp = opentracing::SystemTime::time_point::clock::now(); + options.start_steady_timestamp = opentracing::SteadyTime::time_point::clock::now(); + options.references = {{opentracing::SpanReferenceType::FollowsFromRef, span_context}, + {opentracing::SpanReferenceType::FollowsFromRef, nullptr}}; + + auto options_shim = shim::utils::makeOptionsShim(options); + ASSERT_EQ(options_shim.start_system_time, + common::SystemTimestamp{options.start_system_timestamp}); + ASSERT_EQ(options_shim.start_steady_time, + common::SteadyTimestamp{options.start_steady_timestamp}); + ASSERT_EQ(nostd::get(options_shim.parent), span_context_shim->context()); +} + +TEST(ShimUtilsTest, MakeIterableLinks) +{ + auto span_context_shim1 = nostd::shared_ptr(new shim::SpanContextShim( + trace_api::SpanContext::GetInvalid(), baggage::Baggage::GetDefault())); + auto span_context1 = static_cast(span_context_shim1.get()); + auto span_context_shim2 = nostd::shared_ptr(new shim::SpanContextShim( + trace_api::SpanContext::GetInvalid(), baggage::Baggage::GetDefault())); + auto span_context2 = static_cast(span_context_shim2.get()); + + opentracing::StartSpanOptions options; + auto empty = shim::utils::makeIterableLinks(options); + ASSERT_EQ(empty.size(), 0); + + options.references = {{opentracing::SpanReferenceType::FollowsFromRef, nullptr}, + {opentracing::SpanReferenceType::FollowsFromRef, span_context1}, + {opentracing::SpanReferenceType::ChildOfRef, span_context2}}; + auto full = shim::utils::makeIterableLinks(options); + ASSERT_EQ(full.size(), 3); + + std::vector> links; + full.ForEachKeyValue([&links](trace_api::SpanContext ctx, const common::KeyValueIterable &it) { + it.ForEachKeyValue([&links, &ctx](nostd::string_view key, common::AttributeValue value) { + links.emplace_back(ctx, key, value); + return false; + }); + return true; + }); + ASSERT_EQ(links.size(), 2); + + trace_api::SpanContext ctx = trace_api::SpanContext::GetInvalid(); + nostd::string_view key; + common::AttributeValue value; + std::tie(ctx, key, value) = links[0]; + ASSERT_EQ(ctx, span_context_shim1->context()); + ASSERT_EQ(key, "opentracing.ref_type"); + ASSERT_EQ(nostd::get(value), "follows_from"); + std::tie(ctx, key, value) = links[1]; + ASSERT_EQ(ctx, span_context_shim2->context()); + ASSERT_EQ(key, "opentracing.ref_type"); + ASSERT_EQ(nostd::get(value), "child_of"); +} + +TEST(ShimUtilsTest, MakeBaggage_EmptyRefs) +{ + auto baggage = baggage::Baggage::GetDefault()->Set("foo", "bar"); + std::string value; + ASSERT_TRUE(baggage->GetValue("foo", value)); + ASSERT_EQ(value, "bar"); + + auto context = context::RuntimeContext::GetCurrent(); + auto new_context = baggage::SetBaggage(context, baggage); + auto token = context::RuntimeContext::Attach(new_context); + ASSERT_EQ(context::RuntimeContext::GetCurrent(), new_context); + + opentracing::StartSpanOptions options; + auto new_baggage = shim::utils::makeBaggage(options); + ASSERT_TRUE(new_baggage->GetValue("foo", value)); + ASSERT_EQ(value, "bar"); +} + +TEST(ShimUtilsTest, MakeBaggage_NonEmptyRefs) +{ + auto span_context_shim1 = nostd::shared_ptr(new shim::SpanContextShim( + trace_api::SpanContext::GetInvalid(), + baggage::Baggage::GetDefault()->Set("test", "foo")->Set("test1", "hello"))); + auto span_context1 = static_cast(span_context_shim1.get()); + auto span_context_shim2 = nostd::shared_ptr(new shim::SpanContextShim( + trace_api::SpanContext::GetInvalid(), + baggage::Baggage::GetDefault()->Set("test", "bar")->Set("test2", "world"))); + auto span_context2 = static_cast(span_context_shim2.get()); + + opentracing::StartSpanOptions options; + options.references = {{opentracing::SpanReferenceType::FollowsFromRef, span_context1}, + {opentracing::SpanReferenceType::ChildOfRef, span_context2}}; + + auto baggage = shim::utils::makeBaggage(options); + std::string value; + ASSERT_TRUE(baggage->GetValue("test", value)); + ASSERT_EQ(value, "foo"); + ASSERT_TRUE(baggage->GetValue("test1", value)); + ASSERT_EQ(value, "hello"); + ASSERT_TRUE(baggage->GetValue("test2", value)); + ASSERT_EQ(value, "world"); +} + +TEST(ShimUtilsTest, MakeIterableTags) +{ + opentracing::StartSpanOptions options; + auto empty = shim::utils::makeIterableTags(options); + ASSERT_EQ(empty.size(), 0); + + options.tags = {{"foo", 42.0}, {"bar", true}, {"baz", "test"}}; + auto full = shim::utils::makeIterableTags(options); + ASSERT_EQ(full.size(), 3); + + std::vector> attributes; + full.ForEachKeyValue([&attributes](nostd::string_view key, common::AttributeValue value) { + attributes.push_back({key, value}); + return true; + }); + ASSERT_EQ(attributes[0].first, "foo"); + ASSERT_EQ(nostd::get(attributes[0].second), 42.0); + ASSERT_EQ(attributes[1].first, "bar"); + ASSERT_TRUE(nostd::get(attributes[1].second)); + ASSERT_EQ(attributes[2].first, "baz"); + ASSERT_STREQ(nostd::get(attributes[2].second), "test"); +} diff --git a/opentracing-shim/test/span_context_shim_test.cc b/opentracing-shim/test/span_context_shim_test.cc new file mode 100644 index 0000000000..93978f079a --- /dev/null +++ b/opentracing-shim/test/span_context_shim_test.cc @@ -0,0 +1,108 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "opentelemetry/opentracingshim/span_context_shim.h" + +#include "opentelemetry/baggage/baggage.h" +#include "opentelemetry/trace/span_context.h" + +#include "opentracing/noop.h" + +#include + +namespace trace_api = opentelemetry::trace; +namespace baggage = opentelemetry::baggage; +namespace nostd = opentelemetry::nostd; +namespace shim = opentelemetry::opentracingshim; + +class SpanContextShimTest : public testing::Test +{ +public: + nostd::unique_ptr span_context_shim; + +protected: + virtual void SetUp() override + { + auto span_context = trace_api::SpanContext::GetInvalid(); + auto baggage = baggage::Baggage::GetDefault()->Set("foo", "bar"); + span_context_shim = + nostd::unique_ptr(new shim::SpanContextShim(span_context, baggage)); + } + + virtual void TearDown() override { span_context_shim.reset(); } +}; + +TEST_F(SpanContextShimTest, ExtractFrom) +{ + ASSERT_TRUE(shim::SpanContextShim::extractFrom(nullptr) == nullptr); + + auto tracer = opentracing::MakeNoopTracer(); + auto span = tracer->StartSpanWithOptions("operation", {}); + ASSERT_TRUE(shim::SpanContextShim::extractFrom(&span->context()) == nullptr); + + auto span_context_shim = nostd::shared_ptr(new shim::SpanContextShim( + trace_api::SpanContext::GetInvalid(), baggage::Baggage::GetDefault())); + ASSERT_TRUE(shim::SpanContextShim::extractFrom(span_context_shim.get()) != nullptr); +} + +TEST_F(SpanContextShimTest, BaggageItem) +{ + std::string value; + ASSERT_TRUE(span_context_shim->BaggageItem("foo", value)); + ASSERT_EQ(value, "bar"); + ASSERT_FALSE(span_context_shim->BaggageItem("", value)); +} + +TEST_F(SpanContextShimTest, NewWithKeyValue) +{ + auto new_span_context_shim = span_context_shim->newWithKeyValue("test", "this"); + ASSERT_NE(span_context_shim.get(), &new_span_context_shim); + ASSERT_EQ(span_context_shim->context(), new_span_context_shim.context()); + ASSERT_EQ(span_context_shim->context().IsValid(), new_span_context_shim.context().IsValid()); + ASSERT_EQ(span_context_shim->context().IsRemote(), new_span_context_shim.context().IsRemote()); + + std::string value; + ASSERT_TRUE(new_span_context_shim.BaggageItem("foo", value)); + ASSERT_EQ(value, "bar"); + ASSERT_TRUE(new_span_context_shim.BaggageItem("test", value)); + ASSERT_EQ(value, "this"); +} + +TEST_F(SpanContextShimTest, ForeachBaggageItem) +{ + std::initializer_list> list{ + {"foo", "bar"}, {"bar", "baz"}, {"baz", "foo"}}; + nostd::shared_ptr baggage(new baggage::Baggage(list)); + shim::SpanContextShim new_span_context_shim(span_context_shim->context(), baggage); + + std::vector concatenated; + new_span_context_shim.ForeachBaggageItem( + [&concatenated](const std::string &key, const std::string &value) { + concatenated.emplace_back(key + ":" + value); + return true; + }); + + ASSERT_EQ(concatenated.size(), 3); + ASSERT_EQ(concatenated[0], "foo:bar"); + ASSERT_EQ(concatenated[1], "bar:baz"); + ASSERT_EQ(concatenated[2], "baz:foo"); +} + +TEST_F(SpanContextShimTest, Clone) +{ + auto new_span_context = span_context_shim->Clone(); + auto new_span_context_shim = static_cast(new_span_context.get()); + ASSERT_TRUE(new_span_context_shim != nullptr); + ASSERT_NE(span_context_shim.get(), new_span_context_shim); + ASSERT_EQ(span_context_shim->context(), new_span_context_shim->context()); + ASSERT_EQ(span_context_shim->context().IsValid(), new_span_context_shim->context().IsValid()); + ASSERT_EQ(span_context_shim->context().IsRemote(), new_span_context_shim->context().IsRemote()); + + std::string value; + std::string new_value; + ASSERT_TRUE(span_context_shim->BaggageItem("foo", value)); + ASSERT_TRUE(new_span_context_shim->BaggageItem("foo", new_value)); + ASSERT_EQ(value, new_value); +} diff --git a/opentracing-shim/test/span_shim_test.cc b/opentracing-shim/test/span_shim_test.cc new file mode 100644 index 0000000000..d73f3e0061 --- /dev/null +++ b/opentracing-shim/test/span_shim_test.cc @@ -0,0 +1,225 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "shim_mocks.h" + +#include "opentelemetry/opentracingshim/span_shim.h" +#include "opentelemetry/opentracingshim/tracer_shim.h" + +#include + +namespace trace_api = opentelemetry::trace; +namespace baggage = opentelemetry::baggage; +namespace nostd = opentelemetry::nostd; +namespace shim = opentelemetry::opentracingshim; + +class SpanShimTest : public testing::Test +{ +public: + nostd::unique_ptr span_shim; + MockSpan *mock_span; + +protected: + virtual void SetUp() override + { + mock_span = new MockSpan(); + auto span = nostd::shared_ptr(mock_span); + auto tracer = shim::TracerShim::createTracerShim(); + auto tracer_shim = static_cast(tracer.get()); + auto baggage = baggage::Baggage::GetDefault()->Set("baggage", "item"); + span_shim = nostd::unique_ptr(new shim::SpanShim(*tracer_shim, span, baggage)); + } + + virtual void TearDown() override { span_shim.reset(); } +}; + +TEST_F(SpanShimTest, HandleError) +{ + span_shim->handleError(true); + ASSERT_EQ(mock_span->status_.first, trace_api::StatusCode::kError); + span_shim->handleError("true"); + ASSERT_EQ(mock_span->status_.first, trace_api::StatusCode::kError); + span_shim->handleError(false); + ASSERT_EQ(mock_span->status_.first, trace_api::StatusCode::kOk); + span_shim->handleError("false"); + ASSERT_EQ(mock_span->status_.first, trace_api::StatusCode::kOk); + span_shim->handleError(nullptr); + ASSERT_EQ(mock_span->status_.first, trace_api::StatusCode::kUnset); + span_shim->handleError("unknown"); + ASSERT_EQ(mock_span->status_.first, trace_api::StatusCode::kUnset); + span_shim->handleError(42); + ASSERT_EQ(mock_span->status_.first, trace_api::StatusCode::kUnset); +} + +TEST_F(SpanShimTest, FinishWithOptions) +{ + opentracing::FinishSpanOptions options; + options.finish_steady_timestamp = opentracing::SteadyTime::clock::now(); + ASSERT_NE(mock_span->options_.end_steady_time, options.finish_steady_timestamp); + span_shim->FinishWithOptions(options); + ASSERT_EQ(mock_span->options_.end_steady_time, options.finish_steady_timestamp); +} + +TEST_F(SpanShimTest, SetOperationName) +{ + ASSERT_NE(mock_span->name_, "foo"); + span_shim->SetOperationName("foo"); + ASSERT_EQ(mock_span->name_, "foo"); +} + +TEST_F(SpanShimTest, SetTag_Normal) +{ + ASSERT_NE(mock_span->attribute_.first, "foo"); + span_shim->SetTag("foo", "bar"); + ASSERT_EQ(mock_span->attribute_.first, "foo"); + ASSERT_STREQ(nostd::get(mock_span->attribute_.second), "bar"); +} + +TEST_F(SpanShimTest, SetTag_Error) +{ + ASSERT_NE(mock_span->attribute_.first, "error"); + span_shim->SetTag("error", true); + ASSERT_NE(mock_span->attribute_.first, "error"); + span_shim->SetTag("error", "false"); + ASSERT_NE(mock_span->attribute_.first, "error"); + span_shim->SetTag("error", 42); + ASSERT_NE(mock_span->attribute_.first, "error"); + span_shim->SetTag("error", nullptr); + ASSERT_NE(mock_span->attribute_.first, "error"); +} + +TEST_F(SpanShimTest, BaggageItem) +{ + ASSERT_EQ(span_shim->BaggageItem({}), ""); + ASSERT_EQ(span_shim->BaggageItem(""), ""); + ASSERT_EQ(span_shim->BaggageItem("invalid"), ""); + ASSERT_EQ(span_shim->BaggageItem("baggage"), "item"); +} + +TEST_F(SpanShimTest, SetBaggageItem) +{ + span_shim->SetBaggageItem("new", "entry"); + ASSERT_EQ(span_shim->BaggageItem("new"), "entry"); + ASSERT_EQ(span_shim->BaggageItem("baggage"), "item"); + span_shim->SetBaggageItem("empty", ""); + ASSERT_EQ(span_shim->BaggageItem("empty"), ""); + span_shim->SetBaggageItem("no value", {}); + ASSERT_EQ(span_shim->BaggageItem("no value"), ""); +} + +TEST_F(SpanShimTest, SetBaggageItem_MultiThreaded) +{ + auto span = nostd::shared_ptr(new MockSpan()); + auto tracer = shim::TracerShim::createTracerShim(); + auto tracer_shim = static_cast(tracer.get()); + auto baggage = baggage::Baggage::GetDefault(); + shim::SpanShim span_shim(*tracer_shim, span, baggage); + + std::vector threads; + std::vector keys; + std::vector values; + int thread_count = 100; + + for (int index = 0; index < thread_count; ++index) + { + keys.emplace_back("key-" + std::to_string(index)); + values.emplace_back("value-" + std::to_string(index)); + threads.emplace_back( + std::bind(&shim::SpanShim::SetBaggageItem, &span_shim, keys[index], values[index])); + } + + for (auto &thread : threads) + { + thread.join(); + } + + for (int index = 0; index < thread_count; ++index) + { + ASSERT_EQ(span_shim.BaggageItem(keys[index]), values[index]); + } +} + +TEST_F(SpanShimTest, Log_NoEvent) +{ + std::string name; + common::SystemTimestamp timestamp; + std::unordered_map attributes; + + span_shim->Log({{"test", 42}}); + std::tie(name, timestamp, attributes) = mock_span->event_; + + ASSERT_EQ(name, "log"); + ASSERT_EQ(timestamp, common::SystemTimestamp{}); + ASSERT_EQ(attributes.size(), 1); + ASSERT_EQ(nostd::get(attributes["test"]), 42); +} + +TEST_F(SpanShimTest, Log_NoEvent_Timestamp) +{ + std::string name; + common::SystemTimestamp timestamp; + std::unordered_map attributes; + + auto logtime = opentracing::SystemTime::time_point::clock::now(); + span_shim->Log(logtime, {{"foo", "bar"}}); + std::tie(name, timestamp, attributes) = mock_span->event_; + + ASSERT_EQ(name, "log"); + ASSERT_EQ(timestamp, common::SystemTimestamp{logtime}); + ASSERT_EQ(attributes.size(), 1); + ASSERT_STREQ(nostd::get(attributes["foo"]), "bar"); +} + +TEST_F(SpanShimTest, Log_Event) +{ + std::string name; + common::SystemTimestamp timestamp; + std::unordered_map attributes; + + auto logtime = opentracing::SystemTime::time_point::clock::now(); + std::initializer_list> fields{ + {"event", "normal"}, + {"foo", opentracing::string_view{"bar"}}, + {"error.kind", 42}, + {"message", "hello"}, + {"stack", "overflow"}}; + span_shim->Log(logtime, fields); + std::tie(name, timestamp, attributes) = mock_span->event_; + + ASSERT_EQ(name, "normal"); + ASSERT_EQ(timestamp, common::SystemTimestamp{logtime}); + ASSERT_EQ(attributes.size(), 5); + ASSERT_STREQ(nostd::get(attributes["event"]), "normal"); + ASSERT_EQ(nostd::get(attributes["foo"]), nostd::string_view{"bar"}); + ASSERT_EQ(nostd::get(attributes["error.kind"]), 42); + ASSERT_STREQ(nostd::get(attributes["message"]), "hello"); + ASSERT_STREQ(nostd::get(attributes["stack"]), "overflow"); +} + +TEST_F(SpanShimTest, Log_Error) +{ + std::string name; + common::SystemTimestamp timestamp; + std::unordered_map attributes; + + auto logtime = opentracing::SystemTime::time_point::clock::now(); + std::vector> fields{ + {"event", "error"}, + {"foo", opentracing::string_view{"bar"}}, + {"error.kind", 42}, + {"message", "hello"}, + {"stack", "overflow"}}; + span_shim->Log(logtime, fields); + std::tie(name, timestamp, attributes) = mock_span->event_; + + ASSERT_EQ(name, "exception"); + ASSERT_EQ(timestamp, common::SystemTimestamp{logtime}); + ASSERT_EQ(attributes.size(), 5); + ASSERT_STREQ(nostd::get(attributes["event"]), "error"); + ASSERT_EQ(nostd::get(attributes["foo"]), nostd::string_view{"bar"}); + ASSERT_EQ(nostd::get(attributes["exception.type"]), 42); + ASSERT_STREQ(nostd::get(attributes["exception.message"]), "hello"); + ASSERT_STREQ(nostd::get(attributes["exception.stacktrace"]), "overflow"); +} diff --git a/opentracing-shim/test/tracer_shim_test.cc b/opentracing-shim/test/tracer_shim_test.cc new file mode 100644 index 0000000000..7a06175323 --- /dev/null +++ b/opentracing-shim/test/tracer_shim_test.cc @@ -0,0 +1,219 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "shim_mocks.h" + +#include "opentelemetry/opentracingshim/shim_utils.h" +#include "opentelemetry/opentracingshim/span_context_shim.h" +#include "opentelemetry/opentracingshim/span_shim.h" +#include "opentelemetry/opentracingshim/tracer_shim.h" + +#include "opentracing/noop.h" + +#include + +namespace trace_api = opentelemetry::trace; +namespace nostd = opentelemetry::nostd; +namespace context = opentelemetry::context; +namespace baggage = opentelemetry::baggage; +namespace shim = opentelemetry::opentracingshim; + +class TracerShimTest : public testing::Test +{ +public: + std::shared_ptr tracer_shim; + MockPropagator *text_map_format; + MockPropagator *http_headers_format; + +protected: + virtual void SetUp() override + { + using context::propagation::TextMapPropagator; + + text_map_format = new MockPropagator(); + http_headers_format = new MockPropagator(); + + tracer_shim = shim::TracerShim::createTracerShim( + trace_api::Provider::GetTracerProvider(), + {.text_map = nostd::shared_ptr(text_map_format), + .http_headers = nostd::shared_ptr(http_headers_format)}); + } + + virtual void TearDown() override { tracer_shim.reset(); } +}; + +TEST_F(TracerShimTest, TracerName) +{ + auto mock_provider_ptr = new MockTracerProvider(); + nostd::shared_ptr provider(mock_provider_ptr); + ASSERT_NE(shim::TracerShim::createTracerShim(provider), nullptr); + ASSERT_EQ(mock_provider_ptr->library_name_, "opentracing-shim"); +} + +TEST_F(TracerShimTest, SpanReferenceToCreatingTracer) +{ + auto span_shim = tracer_shim->StartSpan("a"); + ASSERT_NE(span_shim, nullptr); + ASSERT_EQ(&span_shim->tracer(), tracer_shim.get()); +} + +TEST_F(TracerShimTest, SpanParentChildRelationship) +{ + auto span_shim1 = tracer_shim->StartSpan("a"); + auto span_shim2 = tracer_shim->StartSpan("b", {opentracing::ChildOf(&span_shim1->context())}); + ASSERT_NE(span_shim1, nullptr); + ASSERT_NE(span_shim2, nullptr); + ASSERT_NE(span_shim1, span_shim2); + ASSERT_EQ(span_shim1->context().ToSpanID(), span_shim2->context().ToSpanID()); + ASSERT_EQ(span_shim1->context().ToTraceID(), span_shim2->context().ToTraceID()); + + auto span_context_shim1 = static_cast(&span_shim1->context()); + auto span_context_shim2 = static_cast(&span_shim2->context()); + ASSERT_TRUE(span_context_shim1 != nullptr); + ASSERT_TRUE(span_context_shim2 != nullptr); + ASSERT_EQ(span_context_shim1->context(), span_context_shim2->context()); +} + +TEST_F(TracerShimTest, TracerGloballyRegistered) +{ + ASSERT_FALSE(opentracing::Tracer::IsGlobalTracerRegistered()); + ASSERT_NE(opentracing::Tracer::InitGlobal(tracer_shim), nullptr); + ASSERT_TRUE(opentracing::Tracer::IsGlobalTracerRegistered()); +} + +TEST_F(TracerShimTest, Close) +{ + tracer_shim->Close(); + auto span_shim = tracer_shim->StartSpan("a"); + ASSERT_TRUE(span_shim == nullptr); +} + +TEST_F(TracerShimTest, SpanHandleErrorTagAtCreation) +{ + auto mock_provider_ptr = new MockTracerProvider(); + nostd::shared_ptr provider(mock_provider_ptr); + auto tracer_shim = shim::TracerShim::createTracerShim(provider); + auto span_shim = tracer_shim->StartSpanWithOptions("test", {}); + ASSERT_TRUE(span_shim != nullptr); + ASSERT_TRUE(mock_provider_ptr->tracer_ != nullptr); + ASSERT_TRUE(mock_provider_ptr->tracer_->span_ != nullptr); + ASSERT_EQ(mock_provider_ptr->tracer_->span_->name_, "test"); + ASSERT_EQ(mock_provider_ptr->tracer_->span_->status_.first, trace_api::StatusCode::kUnset); + + auto span_shim1 = tracer_shim->StartSpanWithOptions("test1", {.tags = {{"event", "normal"}}}); + ASSERT_TRUE(span_shim1 != nullptr); + ASSERT_EQ(mock_provider_ptr->tracer_->span_->name_, "test1"); + ASSERT_EQ(mock_provider_ptr->tracer_->span_->status_.first, trace_api::StatusCode::kUnset); + + auto span_shim2 = tracer_shim->StartSpanWithOptions("test2", {.tags = {{"error", true}}}); + ASSERT_TRUE(span_shim2 != nullptr); + ASSERT_EQ(mock_provider_ptr->tracer_->span_->name_, "test2"); + ASSERT_EQ(mock_provider_ptr->tracer_->span_->status_.first, trace_api::StatusCode::kError); + + auto span_shim3 = tracer_shim->StartSpanWithOptions("test3", {.tags = {{"error", "false"}}}); + ASSERT_TRUE(span_shim3 != nullptr); + ASSERT_EQ(mock_provider_ptr->tracer_->span_->name_, "test3"); + ASSERT_EQ(mock_provider_ptr->tracer_->span_->status_.first, trace_api::StatusCode::kOk); +} + +TEST_F(TracerShimTest, InjectInvalidCarrier) +{ + auto span_shim = tracer_shim->StartSpan("a"); + auto result = tracer_shim->Inject(span_shim->context(), std::cout); + ASSERT_TRUE(opentracing::are_errors_equal(result.error(), opentracing::invalid_carrier_error)); +} + +TEST_F(TracerShimTest, InjectNullContext) +{ + std::unordered_map text_map; + auto noop_tracer = opentracing::MakeNoopTracer(); + auto span = noop_tracer->StartSpan("a"); + auto result = tracer_shim->Inject(span->context(), TextMapCarrier{text_map}); + ASSERT_TRUE( + opentracing::are_errors_equal(result.error(), opentracing::invalid_span_context_error)); + ASSERT_TRUE(text_map.empty()); +} + +TEST_F(TracerShimTest, InjectTextMap) +{ + ASSERT_FALSE(text_map_format->is_injected); + ASSERT_FALSE(http_headers_format->is_injected); + + std::unordered_map text_map; + auto span_shim = tracer_shim->StartSpan("a"); + tracer_shim->Inject(span_shim->context(), TextMapCarrier{text_map}); + ASSERT_TRUE(text_map_format->is_injected); + ASSERT_FALSE(http_headers_format->is_injected); +} + +TEST_F(TracerShimTest, InjectHttpsHeaders) +{ + ASSERT_FALSE(text_map_format->is_injected); + ASSERT_FALSE(http_headers_format->is_injected); + + std::unordered_map text_map; + auto span_shim = tracer_shim->StartSpan("a"); + tracer_shim->Inject(span_shim->context(), HTTPHeadersCarrier{text_map}); + ASSERT_FALSE(text_map_format->is_injected); + ASSERT_TRUE(http_headers_format->is_injected); +} + +TEST_F(TracerShimTest, ExtractInvalidCarrier) +{ + auto result = tracer_shim->Extract(std::cin); + ASSERT_TRUE(opentracing::are_errors_equal(result.error(), opentracing::invalid_carrier_error)); +} + +TEST_F(TracerShimTest, ExtractNullContext) +{ + std::unordered_map text_map; + auto result = tracer_shim->Extract(TextMapCarrier{text_map}); + ASSERT_EQ(result.value(), nullptr); +} + +TEST_F(TracerShimTest, ExtractTextMap) +{ + ASSERT_FALSE(text_map_format->is_extracted); + ASSERT_FALSE(http_headers_format->is_extracted); + + std::unordered_map text_map; + auto result = tracer_shim->Extract(TextMapCarrier{text_map}); + ASSERT_EQ(result.value(), nullptr); + ASSERT_TRUE(text_map_format->is_extracted); + ASSERT_FALSE(http_headers_format->is_extracted); +} + +TEST_F(TracerShimTest, ExtractHttpsHeaders) +{ + ASSERT_FALSE(text_map_format->is_extracted); + ASSERT_FALSE(http_headers_format->is_extracted); + + std::unordered_map text_map; + auto result = tracer_shim->Extract(HTTPHeadersCarrier{text_map}); + ASSERT_EQ(result.value(), nullptr); + ASSERT_FALSE(text_map_format->is_extracted); + ASSERT_TRUE(http_headers_format->is_extracted); +} + +TEST_F(TracerShimTest, ExtractOnlyBaggage) +{ + std::unordered_map text_map; + auto span_shim = tracer_shim->StartSpan("a"); + span_shim->SetBaggageItem("foo", "bar"); + ASSERT_EQ(span_shim->BaggageItem("foo"), "bar"); + + tracer_shim->Inject(span_shim->context(), TextMapCarrier{text_map}); + auto span_context = tracer_shim->Extract(TextMapCarrier{text_map}); + ASSERT_TRUE(span_context.value() != nullptr); + + auto span_context_shim = static_cast(span_context.value().get()); + ASSERT_TRUE(span_context_shim != nullptr); + ASSERT_FALSE(span_context_shim->context().IsValid()); + ASSERT_FALSE(shim::utils::isBaggageEmpty(span_context_shim->baggage())); + + std::string value; + ASSERT_TRUE(span_context_shim->BaggageItem("foo", value)); + ASSERT_EQ(value, "bar"); +} diff --git a/sdk/BUILD b/sdk/BUILD index cc62431b53..b19ae921e5 100644 --- a/sdk/BUILD +++ b/sdk/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + package(default_visibility = ["//visibility:public"]) cc_library( diff --git a/sdk/CHANGELOG.md b/sdk/CHANGELOG.md deleted file mode 100644 index 8463575d2b..0000000000 --- a/sdk/CHANGELOG.md +++ /dev/null @@ -1,27 +0,0 @@ -# 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/sdk/CMakeLists.txt b/sdk/CMakeLists.txt index c3466b7776..2e8f3bb61d 100644 --- a/sdk/CMakeLists.txt +++ b/sdk/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + add_library(opentelemetry_sdk INTERFACE) target_include_directories( opentelemetry_sdk @@ -6,30 +9,32 @@ target_include_directories( 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() +if(OPENTELEMETRY_INSTALL) + 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") -install( - DIRECTORY include/opentelemetry/sdk - DESTINATION include/opentelemetry - FILES_MATCHING - PATTERN "*.h" - PATTERN "${LOGS_EXCLUDE_PATTERN}" EXCLUDE) + set(LOGS_EXCLUDE_PATTERN "") + if(NOT WITH_LOGS_PREVIEW) + set(LOGS_EXCLUDE_PATTERN "logs") + endif() + + install( + DIRECTORY include/opentelemetry/sdk + DESTINATION include/opentelemetry + FILES_MATCHING + PATTERN "*.h" + PATTERN "${LOGS_EXCLUDE_PATTERN}" EXCLUDE) +endif() add_subdirectory(src) diff --git a/sdk/include/opentelemetry/sdk/common/attributemap_hash.h b/sdk/include/opentelemetry/sdk/common/attributemap_hash.h index c6f2c93ccc..086f6b7901 100644 --- a/sdk/include/opentelemetry/sdk/common/attributemap_hash.h +++ b/sdk/include/opentelemetry/sdk/common/attributemap_hash.h @@ -3,7 +3,6 @@ #pragma once -#include #include #include "opentelemetry/sdk/common/attribute_utils.h" @@ -14,7 +13,7 @@ namespace common { template -inline void GetHashForAttributeValue(size_t &seed, const T arg) +inline void GetHash(size_t &seed, const T &arg) { std::hash hasher; // reference - @@ -23,11 +22,11 @@ inline void GetHashForAttributeValue(size_t &seed, const T arg) } template -inline void GetHashForAttributeValue(size_t &seed, const std::vector &arg) +inline void GetHash(size_t &seed, const std::vector &arg) { for (auto v : arg) { - GetHashForAttributeValue(seed, v); + GetHash(seed, v); } } @@ -37,7 +36,7 @@ struct GetHashForAttributeValueVisitor template void operator()(T &v) { - GetHashForAttributeValue(seed_, v); + GetHash(seed_, v); } size_t &seed_; }; @@ -48,15 +47,40 @@ inline size_t GetHashForAttributeMap(const OrderedAttributeMap &attribute_map) size_t seed = 0UL; for (auto &kv : attribute_map) { - std::hash 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); + GetHash(seed, kv.first); nostd::visit(GetHashForAttributeValueVisitor(seed), kv.second); } return seed; } +// Calculate hash of keys and values of KeyValueIterable, filtered using callback. +inline size_t GetHashForAttributeMap( + const opentelemetry::common::KeyValueIterable &attributes, + nostd::function_ref is_key_present_callback) +{ + AttributeConverter converter; + size_t seed = 0UL; + attributes.ForEachKeyValue( + [&](nostd::string_view key, opentelemetry::common::AttributeValue value) noexcept { + if (!is_key_present_callback(key)) + { + return true; + } + GetHash(seed, key.data()); + auto attr_val = nostd::visit(converter, value); + nostd::visit(GetHashForAttributeValueVisitor(seed), attr_val); + return true; + }); + return seed; +} + +template +inline size_t GetHash(T value) +{ + std::hash hasher; + return hasher(value); +} + } // namespace common } // namespace sdk OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/include/opentelemetry/sdk/common/env_variables.h b/sdk/include/opentelemetry/sdk/common/env_variables.h index be955ee86a..a02a66c29e 100644 --- a/sdk/include/opentelemetry/sdk/common/env_variables.h +++ b/sdk/include/opentelemetry/sdk/common/env_variables.h @@ -3,7 +3,9 @@ #pragma once +#include #include + #include "opentelemetry/version.h" OPENTELEMETRY_BEGIN_NAMESPACE @@ -12,6 +14,31 @@ namespace sdk namespace common { +/** + Read a boolean environment variable. + @param env_var_name Environment variable name + @param [out] value Variable value, if it exists + @return true if the variable exists +*/ +bool GetBoolEnvironmentVariable(const char *env_var_name, bool &value); + +/** + Read a duration environment variable. + @param env_var_name Environment variable name + @param [out] value Variable value, if it exists + @return true if the variable exists +*/ +bool GetDurationEnvironmentVariable(const char *env_var_name, + std::chrono::system_clock::duration &value); + +/** + Read a string environment variable. + @param env_var_name Environment variable name + @param [out] value Variable value, if it exists + @return true if the variable exists +*/ +bool GetStringEnvironmentVariable(const char *env_var_name, std::string &value); + #if defined(_MSC_VER) inline int setenv(const char *name, const char *value, int) { @@ -24,30 +51,6 @@ inline int unsetenv(const char *name) } #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 endpoint_buffer; - if (required_size > 0) - { - endpoint_buffer = std::unique_ptr{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/sdk/include/opentelemetry/sdk/instrumentationscope/instrumentation_scope.h b/sdk/include/opentelemetry/sdk/instrumentationscope/instrumentation_scope.h index c24b4993d2..5d75e61f75 100644 --- a/sdk/include/opentelemetry/sdk/instrumentationscope/instrumentation_scope.h +++ b/sdk/include/opentelemetry/sdk/instrumentationscope/instrumentation_scope.h @@ -3,8 +3,11 @@ #pragma once +#include "opentelemetry/common/key_value_iterable.h" +#include "opentelemetry/common/key_value_iterable_view.h" #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/nostd/unique_ptr.h" +#include "opentelemetry/sdk/common/attribute_utils.h" #include "opentelemetry/version.h" #include @@ -17,6 +20,8 @@ namespace sdk namespace instrumentationscope { +using InstrumentationScopeAttributes = opentelemetry::sdk::common::AttributeMap; + class InstrumentationScope { public: @@ -27,14 +32,65 @@ class InstrumentationScope * @param name name of the instrumentation scope. * @param version version of the instrumentation scope. * @param schema_url schema url of the telemetry emitted by the library. + * @param attributes attributes of the instrumentation scope. * @returns the newly created InstrumentationScope. */ - static nostd::unique_ptr Create(nostd::string_view name, - nostd::string_view version = "", - nostd::string_view schema_url = "") + static nostd::unique_ptr Create( + nostd::string_view name, + nostd::string_view version = "", + nostd::string_view schema_url = "", + InstrumentationScopeAttributes &&attributes = {}) { return nostd::unique_ptr( + new InstrumentationScope{name, version, schema_url, std::move(attributes)}); + } + + /** + * Returns a newly created InstrumentationScope with the specified library name and version. + * @param name name of the instrumentation scope. + * @param version version of the instrumentation scope. + * @param schema_url schema url of the telemetry emitted by the library. + * @param attributes attributes of the instrumentation scope. + * @returns the newly created InstrumentationScope. + */ + static nostd::unique_ptr Create( + nostd::string_view name, + nostd::string_view version, + nostd::string_view schema_url, + const InstrumentationScopeAttributes &attributes) + { + return nostd::unique_ptr(new InstrumentationScope{ + name, version, schema_url, InstrumentationScopeAttributes(attributes)}); + } + + /** + * Returns a newly created InstrumentationScope with the specified library name and version. + * @param name name of the instrumentation scope. + * @param version version of the instrumentation scope. + * @param schema_url schema url of the telemetry emitted by the library. + * @param arg arguments used to create attributes of the instrumentation scope. + * @returns the newly created InstrumentationScope. + */ + template < + class ArgumentType, + nostd::enable_if_t::value> + * = nullptr> + static nostd::unique_ptr Create(nostd::string_view name, + nostd::string_view version, + nostd::string_view schema_url, + const ArgumentType &arg) + { + nostd::unique_ptr result = nostd::unique_ptr( new InstrumentationScope{name, version, schema_url}); + + // Do not construct a KeyValueIterable, so it has better performance. + result->attributes_.reserve(opentelemetry::nostd::size(arg)); + for (auto &argv : arg) + { + result->SetAttribute(argv.first, argv.second); + } + + return result; } std::size_t HashCode() const noexcept { return hash_code_; } @@ -44,7 +100,7 @@ class InstrumentationScope * @param other the instrumentation scope to compare to. * @returns true if the 2 instrumentation libraries are equal, false otherwise. */ - bool operator==(const InstrumentationScope &other) const + bool operator==(const InstrumentationScope &other) const noexcept { return equal(other.name_, other.version_, other.schema_url_); } @@ -60,20 +116,28 @@ class InstrumentationScope */ bool equal(const nostd::string_view name, const nostd::string_view version, - const nostd::string_view schema_url = "") const + const nostd::string_view schema_url = "") const noexcept { 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_; } + const std::string &GetName() const noexcept { return name_; } + const std::string &GetVersion() const noexcept { return version_; } + const std::string &GetSchemaURL() const noexcept { return schema_url_; } + const InstrumentationScopeAttributes &GetAttributes() const noexcept { return attributes_; } + + void SetAttribute(nostd::string_view key, + const opentelemetry::common::AttributeValue &value) noexcept + { + attributes_[std::string(key)] = nostd::visit(common::AttributeConverter(), value); + } private: InstrumentationScope(nostd::string_view name, nostd::string_view version, - nostd::string_view schema_url = "") - : name_(name), version_(version), schema_url_(schema_url) + nostd::string_view schema_url = "", + InstrumentationScopeAttributes &&attributes = {}) + : name_(name), version_(version), schema_url_(schema_url), attributes_(std::move(attributes)) { std::string hash_data; hash_data.reserve(name_.size() + version_.size() + schema_url_.size()); @@ -88,6 +152,8 @@ class InstrumentationScope std::string version_; std::string schema_url_; std::size_t hash_code_; + + InstrumentationScopeAttributes attributes_; }; } // namespace instrumentationscope diff --git a/sdk/include/opentelemetry/sdk/logs/batch_log_record_processor.h b/sdk/include/opentelemetry/sdk/logs/batch_log_record_processor.h index 0621316dcd..d13e8782f1 100644 --- a/sdk/include/opentelemetry/sdk/logs/batch_log_record_processor.h +++ b/sdk/include/opentelemetry/sdk/logs/batch_log_record_processor.h @@ -117,6 +117,7 @@ class BatchLogRecordProcessor : public LogRecordProcessor std::atomic is_force_wakeup_background_worker; std::atomic is_force_flush_pending; std::atomic is_force_flush_notified; + std::atomic force_flush_timeout_us; std::atomic is_shutdown; }; @@ -128,6 +129,7 @@ class BatchLogRecordProcessor : public LogRecordProcessor * @param synchronization_data Synchronization data to be notified. */ static void NotifyCompletion(bool notify_force_flush, + const std::unique_ptr &exporter, const std::shared_ptr &synchronization_data); void GetWaitAdjustedTime(std::chrono::microseconds &timeout, diff --git a/sdk/include/opentelemetry/sdk/logs/batch_log_record_processor_factory.h b/sdk/include/opentelemetry/sdk/logs/batch_log_record_processor_factory.h index ea26fcd1ec..55adc68f72 100644 --- a/sdk/include/opentelemetry/sdk/logs/batch_log_record_processor_factory.h +++ b/sdk/include/opentelemetry/sdk/logs/batch_log_record_processor_factory.h @@ -21,7 +21,7 @@ namespace logs /** * Factory class for BatchLogRecordProcessor. */ -class BatchLogRecordProcessorFactory +class OPENTELEMETRY_EXPORT BatchLogRecordProcessorFactory { public: /** diff --git a/sdk/include/opentelemetry/sdk/logs/event_logger.h b/sdk/include/opentelemetry/sdk/logs/event_logger.h new file mode 100644 index 0000000000..85ad924766 --- /dev/null +++ b/sdk/include/opentelemetry/sdk/logs/event_logger.h @@ -0,0 +1,52 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once +#ifdef ENABLE_LOGS_PREVIEW + +# include +# include + +# include "opentelemetry/common/macros.h" +# include "opentelemetry/logs/event_logger.h" +# include "opentelemetry/logs/logger.h" +# include "opentelemetry/nostd/unique_ptr.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace logs +{ + +class EventLogger final : public opentelemetry::logs::EventLogger +{ +public: + /** + * Initialize a new Eventlogger. + * @param delegate_logger The delegate logger instance + * @param event_domain Event domain + */ + explicit EventLogger(nostd::shared_ptr delegate_logger, + nostd::string_view event_domain) noexcept; + + /** + * Returns the name of this logger. + */ + const opentelemetry::nostd::string_view GetName() noexcept override; + + nostd::shared_ptr GetDelegateLogger() noexcept override; + + using opentelemetry::logs::EventLogger::EmitEvent; + + void EmitEvent(nostd::string_view event_name, + nostd::unique_ptr &&log_record) noexcept override; + +private: + nostd::shared_ptr delegate_logger_; + std::string event_domain_; +}; + +} // namespace logs +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/sdk/include/opentelemetry/sdk/logs/event_logger_provider.h b/sdk/include/opentelemetry/sdk/logs/event_logger_provider.h new file mode 100644 index 0000000000..ba12d94600 --- /dev/null +++ b/sdk/include/opentelemetry/sdk/logs/event_logger_provider.h @@ -0,0 +1,37 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0/ + +#pragma once +#ifdef ENABLE_LOGS_PREVIEW + +# include "opentelemetry/logs/event_logger_provider.h" +# include "opentelemetry/logs/logger.h" +# include "opentelemetry/nostd/shared_ptr.h" +# include "opentelemetry/sdk/logs/logger.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 EventLoggerProvider final : public opentelemetry::logs::EventLoggerProvider +{ +public: + EventLoggerProvider() noexcept; + + ~EventLoggerProvider() override; + + nostd::shared_ptr CreateEventLogger( + nostd::shared_ptr delegate_logger, + nostd::string_view event_domain) noexcept override; +}; +} // namespace logs +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/sdk/include/opentelemetry/sdk/logs/event_logger_provider_factory.h b/sdk/include/opentelemetry/sdk/logs/event_logger_provider_factory.h new file mode 100644 index 0000000000..06aa1c4f2e --- /dev/null +++ b/sdk/include/opentelemetry/sdk/logs/event_logger_provider_factory.h @@ -0,0 +1,32 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0/ + +#pragma once + +#ifdef ENABLE_LOGS_PREVIEW + +# include "opentelemetry/logs/event_logger_provider.h" +# include "opentelemetry/nostd/shared_ptr.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace logs +{ + +/** + * Factory class for EventLoggerProvider. + */ +class EventLoggerProviderFactory +{ +public: + /** + * Create a EventLoggerProvider. + */ + static std::unique_ptr Create(); +}; + +} // namespace logs +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE +#endif /* ENABLE_LOGS_PREVIEW */ diff --git a/sdk/include/opentelemetry/sdk/logs/exporter.h b/sdk/include/opentelemetry/sdk/logs/exporter.h index a531577aef..069fd8784c 100644 --- a/sdk/include/opentelemetry/sdk/logs/exporter.h +++ b/sdk/include/opentelemetry/sdk/logs/exporter.h @@ -20,10 +20,11 @@ namespace logs /** * LogRecordExporter defines the interface that log exporters must implement. */ -class LogRecordExporter +class OPENTELEMETRY_EXPORT LogRecordExporter { public: - virtual ~LogRecordExporter() = default; + LogRecordExporter(); + virtual ~LogRecordExporter(); /** * Create a log recordable. This object will be used to record log data and @@ -47,6 +48,12 @@ class LogRecordExporter virtual sdk::common::ExportResult Export( const nostd::span> &records) noexcept = 0; + /** + * Force flush the log records pushed into this log exporter. + */ + virtual bool ForceFlush( + std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept; + /** * Marks the exporter as ShutDown and cleans up any resources as required. * Shutdown should be called only once for each Exporter instance. diff --git a/sdk/include/opentelemetry/sdk/logs/logger.h b/sdk/include/opentelemetry/sdk/logs/logger.h index d290df98c3..ece83a8b57 100644 --- a/sdk/include/opentelemetry/sdk/logs/logger.h +++ b/sdk/include/opentelemetry/sdk/logs/logger.h @@ -33,7 +33,8 @@ class Logger final : public opentelemetry::logs::Logger opentelemetry::nostd::string_view name, std::shared_ptr context, std::unique_ptr instrumentation_scope = - instrumentationscope::InstrumentationScope::Create("")) noexcept; + instrumentationscope::InstrumentationScope::Create(""), + bool include_trace_context = true) noexcept; /** * Returns the name of this logger. @@ -66,6 +67,8 @@ class Logger final : public opentelemetry::logs::Logger // logger-context. std::unique_ptr instrumentation_scope_; std::shared_ptr context_; + + bool include_trace_context_; }; } // namespace logs diff --git a/sdk/include/opentelemetry/sdk/logs/logger_provider.h b/sdk/include/opentelemetry/sdk/logs/logger_provider.h index fd38532752..a52c1a7220 100644 --- a/sdk/include/opentelemetry/sdk/logs/logger_provider.h +++ b/sdk/include/opentelemetry/sdk/logs/logger_provider.h @@ -63,38 +63,24 @@ class LoggerProvider final : public opentelemetry::logs::LoggerProvider ~LoggerProvider() override; + using opentelemetry::logs::LoggerProvider::GetLogger; + /** * 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 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 GetLogger( nostd::string_view logger_name, - nostd::span args, nostd::string_view library_name, nostd::string_view library_version = "", - nostd::string_view schema_url = "") noexcept override; + nostd::string_view schema_url = "", + bool include_trace_context = true, + const opentelemetry::common::KeyValueIterable &attributes = + opentelemetry::common::NoopKeyValueIterable()) noexcept override; /** * Add the processor that is stored internally in the logger provider. diff --git a/sdk/include/opentelemetry/sdk/logs/logger_provider_factory.h b/sdk/include/opentelemetry/sdk/logs/logger_provider_factory.h index e103fce8be..0795129df3 100644 --- a/sdk/include/opentelemetry/sdk/logs/logger_provider_factory.h +++ b/sdk/include/opentelemetry/sdk/logs/logger_provider_factory.h @@ -24,7 +24,7 @@ namespace logs /** * Factory class for LoggerProvider. */ -class LoggerProviderFactory +class OPENTELEMETRY_EXPORT LoggerProviderFactory { public: /** diff --git a/sdk/include/opentelemetry/sdk/logs/multi_log_record_processor_factory.h b/sdk/include/opentelemetry/sdk/logs/multi_log_record_processor_factory.h index 0e8b9a5878..c91cad52ff 100644 --- a/sdk/include/opentelemetry/sdk/logs/multi_log_record_processor_factory.h +++ b/sdk/include/opentelemetry/sdk/logs/multi_log_record_processor_factory.h @@ -19,7 +19,7 @@ namespace logs /** * Factory class for MultiLogRecordProcessor. */ -class MultiLogRecordProcessorFactory +class OPENTELEMETRY_EXPORT MultiLogRecordProcessorFactory { public: static std::unique_ptr Create( diff --git a/sdk/include/opentelemetry/sdk/logs/simple_log_record_processor_factory.h b/sdk/include/opentelemetry/sdk/logs/simple_log_record_processor_factory.h index a71ba05684..aec65349c5 100644 --- a/sdk/include/opentelemetry/sdk/logs/simple_log_record_processor_factory.h +++ b/sdk/include/opentelemetry/sdk/logs/simple_log_record_processor_factory.h @@ -19,7 +19,7 @@ namespace logs /** * Factory class for SimpleLogRecordProcessor. */ -class SimpleLogRecordProcessorFactory +class OPENTELEMETRY_EXPORT SimpleLogRecordProcessorFactory { public: /** diff --git a/sdk/include/opentelemetry/sdk/metrics/aggregation/aggregation_config.h b/sdk/include/opentelemetry/sdk/metrics/aggregation/aggregation_config.h index ee297881d0..69dc4c8864 100644 --- a/sdk/include/opentelemetry/sdk/metrics/aggregation/aggregation_config.h +++ b/sdk/include/opentelemetry/sdk/metrics/aggregation/aggregation_config.h @@ -3,8 +3,10 @@ #pragma once -#include #include "opentelemetry/version.h" + +#include + OPENTELEMETRY_BEGIN_NAMESPACE namespace sdk { @@ -19,7 +21,7 @@ class AggregationConfig class HistogramAggregationConfig : public AggregationConfig { public: - std::list boundaries_; + std::vector boundaries_; bool record_min_max_ = true; }; } // namespace metrics diff --git a/sdk/include/opentelemetry/sdk/metrics/aggregation/default_aggregation.h b/sdk/include/opentelemetry/sdk/metrics/aggregation/default_aggregation.h index b704a4cee4..c4890db314 100644 --- a/sdk/include/opentelemetry/sdk/metrics/aggregation/default_aggregation.h +++ b/sdk/include/opentelemetry/sdk/metrics/aggregation/default_aggregation.h @@ -92,7 +92,8 @@ class DefaultAggregation case AggregationType::kSum: { bool is_monotonic = true; if (instrument_descriptor.type_ == InstrumentType::kUpDownCounter || - instrument_descriptor.type_ == InstrumentType::kObservableUpDownCounter) + instrument_descriptor.type_ == InstrumentType::kObservableUpDownCounter || + instrument_descriptor.type_ == InstrumentType::kHistogram) { is_monotonic = false; } diff --git a/sdk/include/opentelemetry/sdk/metrics/aggregation/histogram_aggregation.h b/sdk/include/opentelemetry/sdk/metrics/aggregation/histogram_aggregation.h index ae9eeb4ded..5d1097d93f 100644 --- a/sdk/include/opentelemetry/sdk/metrics/aggregation/histogram_aggregation.h +++ b/sdk/include/opentelemetry/sdk/metrics/aggregation/histogram_aggregation.h @@ -108,6 +108,13 @@ void HistogramDiff(HistogramPointData ¤t, HistogramPointData &next, Histog diff.record_min_max_ = false; } +template +size_t BucketBinarySearch(T value, const std::vector &boundaries) +{ + auto low = std::lower_bound(boundaries.begin(), boundaries.end(), value); + return low - boundaries.begin(); +} + } // namespace metrics } // namespace sdk OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/include/opentelemetry/sdk/metrics/data/point_data.h b/sdk/include/opentelemetry/sdk/metrics/data/point_data.h index 359da0b864..62ba3df1bc 100644 --- a/sdk/include/opentelemetry/sdk/metrics/data/point_data.h +++ b/sdk/include/opentelemetry/sdk/metrics/data/point_data.h @@ -8,7 +8,7 @@ #include "opentelemetry/sdk/metrics/instruments.h" #include "opentelemetry/version.h" -#include +#include OPENTELEMETRY_BEGIN_NAMESPACE namespace sdk @@ -55,14 +55,14 @@ class HistogramPointData HistogramPointData &operator=(HistogramPointData &&) = default; HistogramPointData(const HistogramPointData &) = default; HistogramPointData() = default; - HistogramPointData(std::list &boundaries) : boundaries_(boundaries) {} - std::list boundaries_ = {}; - ValueType sum_ = {}; - ValueType min_ = {}; - ValueType max_ = {}; - std::vector counts_ = {}; - uint64_t count_ = {}; - bool record_min_max_ = true; + HistogramPointData(std::vector &boundaries) : boundaries_(boundaries) {} + std::vector boundaries_ = {}; + ValueType sum_ = {}; + ValueType min_ = {}; + ValueType max_ = {}; + std::vector counts_ = {}; + uint64_t count_ = {}; + bool record_min_max_ = true; }; class DropPointData diff --git a/sdk/include/opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader.h b/sdk/include/opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader.h index 96b37f0d40..83773ffb61 100644 --- a/sdk/include/opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader.h +++ b/sdk/include/opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader.h @@ -57,13 +57,17 @@ class PeriodicExportingMetricReader : public MetricReader std::chrono::milliseconds export_timeout_millis_; void DoBackgroundWork(); + bool CollectAndExportOnce(); /* The background worker thread */ std::thread worker_thread_; /* Synchronization primitives */ - std::condition_variable cv_; - std::mutex cv_m_; + std::atomic is_force_flush_pending_; + std::atomic is_force_wakeup_background_worker_; + std::atomic is_force_flush_notified_; + std::condition_variable cv_, force_flush_cv_; + std::mutex cv_m_, force_flush_m_; }; } // namespace metrics diff --git a/sdk/include/opentelemetry/sdk/metrics/instrument_metadata_validator.h b/sdk/include/opentelemetry/sdk/metrics/instrument_metadata_validator.h index 0a8362e9e9..95848a8eec 100644 --- a/sdk/include/opentelemetry/sdk/metrics/instrument_metadata_validator.h +++ b/sdk/include/opentelemetry/sdk/metrics/instrument_metadata_validator.h @@ -8,7 +8,7 @@ #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/version.h" -#if HAVE_WORKING_REGEX +#if OPENTELEMETRY_HAVE_WORKING_REGEX # include #endif @@ -26,7 +26,7 @@ class InstrumentMetaDataValidator bool ValidateDescription(nostd::string_view description) const; private: -#if HAVE_WORKING_REGEX +#if OPENTELEMETRY_HAVE_WORKING_REGEX const std::regex name_reg_key_; const std::regex unit_reg_key_; #endif diff --git a/sdk/include/opentelemetry/sdk/metrics/metric_reader.h b/sdk/include/opentelemetry/sdk/metrics/metric_reader.h index d7d6bcbd39..86101e39a0 100644 --- a/sdk/include/opentelemetry/sdk/metrics/metric_reader.h +++ b/sdk/include/opentelemetry/sdk/metrics/metric_reader.h @@ -45,7 +45,7 @@ class MetricReader InstrumentType instrument_type) const noexcept = 0; /** - * Shutdown the meter reader. + * Shutdown the metric reader. */ bool Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept; @@ -54,6 +54,11 @@ class MetricReader */ bool ForceFlush(std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept; + /** + * Return the status of Metric reader. + */ + bool IsShutdown() const noexcept; + virtual ~MetricReader() = default; private: @@ -64,8 +69,6 @@ class MetricReader virtual void OnInitialized() noexcept {} protected: - bool IsShutdown() const noexcept; - private: MetricProducer *metric_producer_; mutable opentelemetry::common::SpinLockMutex lock_; diff --git a/sdk/include/opentelemetry/sdk/metrics/state/async_metric_storage.h b/sdk/include/opentelemetry/sdk/metrics/state/async_metric_storage.h index 69920547ba..aad00bb5cf 100644 --- a/sdk/include/opentelemetry/sdk/metrics/state/async_metric_storage.h +++ b/sdk/include/opentelemetry/sdk/metrics/state/async_metric_storage.h @@ -27,16 +27,12 @@ class AsyncMetricStorage : public MetricStorage, public AsyncWritableMetricStora public: AsyncMetricStorage(InstrumentDescriptor instrument_descriptor, const AggregationType aggregation_type, - const AttributesProcessor *attributes_processor, - const AggregationConfig *aggregation_config, - void *state = nullptr) + const AggregationConfig *aggregation_config) : instrument_descriptor_(instrument_descriptor), aggregation_type_{aggregation_type}, - attributes_processor_{attributes_processor}, - state_{state}, cumulative_hash_map_(new AttributesHashMap()), delta_hash_map_(new AttributesHashMap()), - temporal_metric_storage_(instrument_descriptor, aggregation_config) + temporal_metric_storage_(instrument_descriptor, aggregation_type, aggregation_config) {} template @@ -51,22 +47,24 @@ class AsyncMetricStorage : public MetricStorage, public AsyncWritableMetricStora { auto aggr = DefaultAggregation::CreateAggregation(aggregation_type_, instrument_descriptor_); aggr->Aggregate(measurement.second); - auto prev = cumulative_hash_map_->Get(measurement.first); + auto hash = opentelemetry::sdk::common::GetHashForAttributeMap(measurement.first); + auto prev = cumulative_hash_map_->Get(hash); if (prev) { auto delta = prev->Diff(*aggr); // store received value in cumulative map, and the diff in delta map (to pass it to temporal // storage) - cumulative_hash_map_->Set(measurement.first, std::move(aggr)); - delta_hash_map_->Set(measurement.first, std::move(delta)); + cumulative_hash_map_->Set(measurement.first, std::move(aggr), hash); + delta_hash_map_->Set(measurement.first, std::move(delta), hash); } else { // store received value in cumulative and delta map. cumulative_hash_map_->Set( measurement.first, - DefaultAggregation::CloneAggregation(aggregation_type_, instrument_descriptor_, *aggr)); - delta_hash_map_->Set(measurement.first, std::move(aggr)); + DefaultAggregation::CloneAggregation(aggregation_type_, instrument_descriptor_, *aggr), + hash); + delta_hash_map_->Set(measurement.first, std::move(aggr), hash); } } } @@ -116,8 +114,6 @@ class AsyncMetricStorage : public MetricStorage, public AsyncWritableMetricStora private: InstrumentDescriptor instrument_descriptor_; AggregationType aggregation_type_; - const AttributesProcessor *attributes_processor_; - void *state_; std::unique_ptr cumulative_hash_map_; std::unique_ptr delta_hash_map_; opentelemetry::common::SpinLockMutex hashmap_lock_; diff --git a/sdk/include/opentelemetry/sdk/metrics/state/attributes_hashmap.h b/sdk/include/opentelemetry/sdk/metrics/state/attributes_hashmap.h index 5b575fd024..a4b53a37c5 100644 --- a/sdk/include/opentelemetry/sdk/metrics/state/attributes_hashmap.h +++ b/sdk/include/opentelemetry/sdk/metrics/state/attributes_hashmap.h @@ -8,6 +8,7 @@ #include "opentelemetry/sdk/common/attributemap_hash.h" #include "opentelemetry/sdk/metrics/aggregation/aggregation.h" #include "opentelemetry/sdk/metrics/instruments.h" +#include "opentelemetry/sdk/metrics/view/attributes_processor.h" #include "opentelemetry/version.h" #include @@ -19,6 +20,7 @@ namespace sdk { namespace metrics { + using opentelemetry::sdk::common::OrderedAttributeMap; class AttributeHashGenerator @@ -33,12 +35,12 @@ class AttributeHashGenerator class AttributesHashMap { public: - Aggregation *Get(const MetricAttributes &attributes) const + Aggregation *Get(size_t hash) const { - auto it = hash_map_.find(attributes); + auto it = hash_map_.find(hash); if (it != hash_map_.end()) { - return it->second.get(); + return it->second.second.get(); } return nullptr; } @@ -47,35 +49,89 @@ class AttributesHashMap * @return check if key is present in hash * */ - bool Has(const MetricAttributes &attributes) const - { - return (hash_map_.find(attributes) == hash_map_.end()) ? false : true; - } + bool Has(size_t hash) const { return hash_map_.find(hash) != hash_map_.end(); } /** * @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 opentelemetry::common::KeyValueIterable &attributes, + std::function()> aggregation_callback, + size_t hash) + { + auto it = hash_map_.find(hash); + if (it != hash_map_.end()) + { + return it->second.second.get(); + } + + MetricAttributes attr{attributes}; + + hash_map_[hash] = {attr, aggregation_callback()}; + return hash_map_[hash].second.get(); + } + + Aggregation *GetOrSetDefault(std::function()> aggregation_callback, + size_t hash) + { + auto it = hash_map_.find(hash); + if (it != hash_map_.end()) + { + return it->second.second.get(); + } + MetricAttributes attr{}; + hash_map_[hash] = {attr, aggregation_callback()}; + return hash_map_[hash].second.get(); + } + Aggregation *GetOrSetDefault(const MetricAttributes &attributes, - std::function()> aggregation_callback) + std::function()> aggregation_callback, + size_t hash) { - auto it = hash_map_.find(attributes); + auto it = hash_map_.find(hash); if (it != hash_map_.end()) { - return it->second.get(); + return it->second.second.get(); } - hash_map_[attributes] = aggregation_callback(); - return hash_map_[attributes].get(); + MetricAttributes attr{attributes}; + + hash_map_[hash] = {attr, aggregation_callback()}; + return hash_map_[hash].second.get(); } /** * Set the value for given key, overwriting the value if already present */ - void Set(const MetricAttributes &attributes, std::unique_ptr value) + void Set(const opentelemetry::common::KeyValueIterable &attributes, + std::unique_ptr aggr, + size_t hash) { - hash_map_[attributes] = std::move(value); + auto it = hash_map_.find(hash); + if (it != hash_map_.end()) + { + it->second.second = std::move(aggr); + } + else + { + MetricAttributes attr{attributes}; + hash_map_[hash] = {attr, std::move(aggr)}; + } + } + + void Set(const MetricAttributes &attributes, std::unique_ptr aggr, size_t hash) + { + auto it = hash_map_.find(hash); + if (it != hash_map_.end()) + { + it->second.second = std::move(aggr); + } + else + { + MetricAttributes attr{attributes}; + hash_map_[hash] = {attr, std::move(aggr)}; + } } /** @@ -86,7 +142,7 @@ class AttributesHashMap { for (auto &kv : hash_map_) { - if (!callback(kv.first, *(kv.second.get()))) + if (!callback(kv.second.first, *(kv.second.second.get()))) { return false; // callback is not prepared to consume data } @@ -100,8 +156,7 @@ class AttributesHashMap size_t Size() { return hash_map_.size(); } private: - std::unordered_map, AttributeHashGenerator> - hash_map_; + std::unordered_map>> hash_map_; }; } // namespace metrics diff --git a/sdk/include/opentelemetry/sdk/metrics/state/sync_metric_storage.h b/sdk/include/opentelemetry/sdk/metrics/state/sync_metric_storage.h index c6a78451af..b8146872e3 100644 --- a/sdk/include/opentelemetry/sdk/metrics/state/sync_metric_storage.h +++ b/sdk/include/opentelemetry/sdk/metrics/state/sync_metric_storage.h @@ -30,25 +30,27 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage SyncMetricStorage(InstrumentDescriptor instrument_descriptor, const AggregationType aggregation_type, const AttributesProcessor *attributes_processor, - nostd::shared_ptr &&exemplar_reservoir, + nostd::shared_ptr &&exemplar_reservoir + OPENTELEMETRY_MAYBE_UNUSED, const AggregationConfig *aggregation_config) : instrument_descriptor_(instrument_descriptor), - aggregation_type_{aggregation_type}, attributes_hashmap_(new AttributesHashMap()), - attributes_processor_{attributes_processor}, + attributes_processor_(attributes_processor), #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW exemplar_reservoir_(exemplar_reservoir), #endif - temporal_metric_storage_(instrument_descriptor, aggregation_config) - + temporal_metric_storage_(instrument_descriptor, aggregation_type, aggregation_config) { - create_default_aggregation_ = [&, aggregation_config]() -> std::unique_ptr { - return DefaultAggregation::CreateAggregation(aggregation_type_, instrument_descriptor_, + create_default_aggregation_ = [&, aggregation_type, + aggregation_config]() -> std::unique_ptr { + return DefaultAggregation::CreateAggregation(aggregation_type, instrument_descriptor_, aggregation_config); }; } - void RecordLong(int64_t value, const opentelemetry::context::Context &context) noexcept override + void RecordLong(int64_t value, + const opentelemetry::context::Context &context + OPENTELEMETRY_MAYBE_UNUSED) noexcept override { if (instrument_descriptor_.value_type_ != InstrumentValueType::kLong) { @@ -57,13 +59,15 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW exemplar_reservoir_->OfferMeasurement(value, {}, context, std::chrono::system_clock::now()); #endif + static size_t hash = opentelemetry::sdk::common::GetHash(""); std::lock_guard guard(attribute_hashmap_lock_); - attributes_hashmap_->GetOrSetDefault({}, create_default_aggregation_)->Aggregate(value); + attributes_hashmap_->GetOrSetDefault(create_default_aggregation_, hash)->Aggregate(value); } void RecordLong(int64_t value, const opentelemetry::common::KeyValueIterable &attributes, - const opentelemetry::context::Context &context) noexcept override + const opentelemetry::context::Context &context + OPENTELEMETRY_MAYBE_UNUSED) noexcept override { if (instrument_descriptor_.value_type_ != InstrumentValueType::kLong) { @@ -73,12 +77,26 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage exemplar_reservoir_->OfferMeasurement(value, attributes, context, std::chrono::system_clock::now()); #endif - auto attr = attributes_processor_->process(attributes); + auto hash = opentelemetry::sdk::common::GetHashForAttributeMap( + attributes, [this](nostd::string_view key) { + if (attributes_processor_) + { + return attributes_processor_->isPresent(key); + } + else + { + return true; + } + }); + std::lock_guard guard(attribute_hashmap_lock_); - attributes_hashmap_->GetOrSetDefault(attr, create_default_aggregation_)->Aggregate(value); + attributes_hashmap_->GetOrSetDefault(attributes, create_default_aggregation_, hash) + ->Aggregate(value); } - void RecordDouble(double value, const opentelemetry::context::Context &context) noexcept override + void RecordDouble(double value, + const opentelemetry::context::Context &context + OPENTELEMETRY_MAYBE_UNUSED) noexcept override { if (instrument_descriptor_.value_type_ != InstrumentValueType::kDouble) { @@ -87,13 +105,15 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW exemplar_reservoir_->OfferMeasurement(value, {}, context, std::chrono::system_clock::now()); #endif + static size_t hash = opentelemetry::sdk::common::GetHash(""); std::lock_guard guard(attribute_hashmap_lock_); - attributes_hashmap_->GetOrSetDefault({}, create_default_aggregation_)->Aggregate(value); + attributes_hashmap_->GetOrSetDefault(create_default_aggregation_, hash)->Aggregate(value); } void RecordDouble(double value, const opentelemetry::common::KeyValueIterable &attributes, - const opentelemetry::context::Context &context) noexcept override + const opentelemetry::context::Context &context + OPENTELEMETRY_MAYBE_UNUSED) noexcept override { #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW exemplar_reservoir_->OfferMeasurement(value, attributes, context, @@ -107,9 +127,20 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage exemplar_reservoir_->OfferMeasurement(value, attributes, context, std::chrono::system_clock::now()); #endif - auto attr = attributes_processor_->process(attributes); + auto hash = opentelemetry::sdk::common::GetHashForAttributeMap( + attributes, [this](nostd::string_view key) { + if (attributes_processor_) + { + return attributes_processor_->isPresent(key); + } + else + { + return true; + } + }); std::lock_guard guard(attribute_hashmap_lock_); - attributes_hashmap_->GetOrSetDefault(attr, create_default_aggregation_)->Aggregate(value); + attributes_hashmap_->GetOrSetDefault(attributes, create_default_aggregation_, hash) + ->Aggregate(value); } bool Collect(CollectorHandle *collector, @@ -120,8 +151,6 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage 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 attributes_hashmap_; // unreported metrics stash for all the collectors @@ -129,8 +158,8 @@ class SyncMetricStorage : public MetricStorage, public SyncWritableMetricStorage unreported_metrics_; // last reported metrics stash for all the collectors. std::unordered_map last_reported_metrics_; - const AttributesProcessor *attributes_processor_; std::function()> create_default_aggregation_; + const AttributesProcessor *attributes_processor_; #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW nostd::shared_ptr exemplar_reservoir_; #endif diff --git a/sdk/include/opentelemetry/sdk/metrics/state/temporal_metric_storage.h b/sdk/include/opentelemetry/sdk/metrics/state/temporal_metric_storage.h index 439ca3cd4d..4ddc593149 100644 --- a/sdk/include/opentelemetry/sdk/metrics/state/temporal_metric_storage.h +++ b/sdk/include/opentelemetry/sdk/metrics/state/temporal_metric_storage.h @@ -8,6 +8,7 @@ #include "opentelemetry/sdk/metrics/state/attributes_hashmap.h" #include "opentelemetry/sdk/metrics/state/metric_collector.h" +#include #include OPENTELEMETRY_BEGIN_NAMESPACE @@ -26,6 +27,7 @@ class TemporalMetricStorage { public: TemporalMetricStorage(InstrumentDescriptor instrument_descriptor, + AggregationType aggregation_type, const AggregationConfig *aggregation_config); bool buildMetrics(CollectorHandle *collector, @@ -37,6 +39,7 @@ class TemporalMetricStorage private: InstrumentDescriptor instrument_descriptor_; + AggregationType aggregation_type_; // unreported metrics stash for all the collectors std::unordered_map>> diff --git a/sdk/include/opentelemetry/sdk/metrics/view/attributes_processor.h b/sdk/include/opentelemetry/sdk/metrics/view/attributes_processor.h index 754f45e1b6..c3328bfa1e 100644 --- a/sdk/include/opentelemetry/sdk/metrics/view/attributes_processor.h +++ b/sdk/include/opentelemetry/sdk/metrics/view/attributes_processor.h @@ -4,6 +4,7 @@ #pragma once #include "opentelemetry/sdk/common/attribute_utils.h" + OPENTELEMETRY_BEGIN_NAMESPACE namespace sdk { @@ -20,10 +21,14 @@ class AttributesProcessor { public: // Process the metric instrument attributes. - // @returns The processed attributes + // @returns integer with individual bits set if they are to be filtered. + virtual MetricAttributes process( const opentelemetry::common::KeyValueIterable &attributes) const noexcept = 0; - virtual ~AttributesProcessor() = default; + + virtual bool isPresent(nostd::string_view key) const noexcept = 0; + + virtual ~AttributesProcessor() = default; }; /** @@ -33,12 +38,15 @@ class AttributesProcessor class DefaultAttributesProcessor : public AttributesProcessor { +public: MetricAttributes process( const opentelemetry::common::KeyValueIterable &attributes) const noexcept override { MetricAttributes result(attributes); return result; } + + bool isPresent(nostd::string_view /*key*/) const noexcept override { return true; } }; /** @@ -70,6 +78,11 @@ class FilteringAttributesProcessor : public AttributesProcessor return result; } + bool isPresent(nostd::string_view key) const noexcept override + { + return (allowed_attribute_keys_.find(key.data()) != allowed_attribute_keys_.end()); + } + private: std::unordered_map allowed_attribute_keys_; }; diff --git a/sdk/include/opentelemetry/sdk/metrics/view/predicate.h b/sdk/include/opentelemetry/sdk/metrics/view/predicate.h index b5dafcf51a..5346a753ff 100644 --- a/sdk/include/opentelemetry/sdk/metrics/view/predicate.h +++ b/sdk/include/opentelemetry/sdk/metrics/view/predicate.h @@ -8,6 +8,10 @@ #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/sdk/common/global_log_handler.h" +#if defined(OPENTELEMETRY_HAVE_WORKING_REGEX) +# include +#endif + OPENTELEMETRY_BEGIN_NAMESPACE namespace sdk { @@ -26,7 +30,7 @@ class PatternPredicate : public Predicate PatternPredicate(opentelemetry::nostd::string_view pattern) : reg_key_{pattern.data()} {} bool Match(opentelemetry::nostd::string_view str) const noexcept override { -#if HAVE_WORKING_REGEX +#if OPENTELEMETRY_HAVE_WORKING_REGEX return std::regex_match(str.data(), reg_key_); #else // TBD - Support regex match for GCC4.8 @@ -37,7 +41,7 @@ class PatternPredicate : public Predicate } private: -#if HAVE_WORKING_REGEX +#if OPENTELEMETRY_HAVE_WORKING_REGEX std::regex reg_key_; #else std::string reg_key_; diff --git a/sdk/include/opentelemetry/sdk/resource/resource.h b/sdk/include/opentelemetry/sdk/resource/resource.h index eee339e237..09da0b8c97 100644 --- a/sdk/include/opentelemetry/sdk/resource/resource.h +++ b/sdk/include/opentelemetry/sdk/resource/resource.h @@ -36,11 +36,15 @@ class Resource * with the other Resource. In case of a collision, the other Resource takes * precedence. * + * The specification notes that if schema urls collide, the resulting + * schema url is implementation-defined. In the C++ implementation, the + * schema url of @param other is picked. + * * @param other the Resource that will be merged with this. * @returns the newly merged Resource. */ - Resource Merge(const Resource &other) noexcept; + Resource Merge(const Resource &other) const noexcept; /** * Returns a newly created Resource with the specified attributes. diff --git a/sdk/include/opentelemetry/sdk/resource/semantic_conventions.h b/sdk/include/opentelemetry/sdk/resource/semantic_conventions.h index 00198d4e7a..f1315d9262 100644 --- a/sdk/include/opentelemetry/sdk/resource/semantic_conventions.h +++ b/sdk/include/opentelemetry/sdk/resource/semantic_conventions.h @@ -23,7 +23,7 @@ namespace SemanticConventions /** * The URL of the OpenTelemetry schema for these keys and values. */ -static constexpr const char *kSchemaUrl = "https://opentelemetry.io/schemas/1.16.0"; +static constexpr const char *kSchemaUrl = "https://opentelemetry.io/schemas/1.20.0"; /** * Array of brand name and version separated by a space @@ -62,16 +62,6 @@ static constexpr const char *kBrowserPlatform = "browser.platform"; */ static constexpr const char *kBrowserMobile = "browser.mobile"; -/** - * Full user-agent string provided by the browser - * - *

Notes: -

  • The user-agent value SHOULD be provided only from browsers that do not have a mechanism - to retrieve brands and platform individually from the User-Agent Client Hints API. To retrieve the - value, the legacy {@code navigator.userAgent} API can be used.
- */ -static constexpr const char *kBrowserUserAgent = "browser.user_agent"; - /** * Preferred language of the user using the browser * @@ -100,11 +90,41 @@ static constexpr const char *kCloudAccountId = "cloud.account.id"; href="https://aws.amazon.com/about-aws/global-infrastructure/regions_az/">AWS regions, Azure regions, Google Cloud regions, or Tencent Cloud regions. - + href="https://www.tencentcloud.com/document/product/213/6091">Tencent Cloud regions. */ static constexpr const char *kCloudRegion = "cloud.region"; +/** + * Cloud provider-specific native identifier of the monitored cloud resource (e.g. an ARN on AWS, a +fully qualified +resource ID on Azure, a full resource name +on GCP) + * + *

Notes: +

  • On some cloud providers, it may not be possible to determine the full ID at startup, +so it may be necessary to set {@code cloud.resource_id} as a span attribute instead.
  • The +exact value to use for {@code cloud.resource_id} depends on the cloud provider. The following +well-known definitions MUST be used if you set this attribute and they apply:
  • AWS +Lambda: The function ARN. Take care +not to use the "invoked ARN" directly but replace any alias suffix with +the resolved function version, as the same runtime instance may be invokable with multiple different +aliases.
  • GCP: The URI of the resource
  • +
  • Azure: The Fully Qualified +Resource ID of the invoked function, not the function app, having the form +{@code +/subscriptions//resourceGroups//providers/Microsoft.Web/sites//functions/}. +This means that a span attribute MUST be used, as an Azure function app can host multiple functions +that would usually share a TracerProvider.
  • +
+ */ +static constexpr const char *kCloudResourceId = "cloud.resource_id"; + /** * Cloud regions often have multiple, isolated locations known as zones to increase availability. Availability zone represents the zone where the resource is running. @@ -201,6 +221,21 @@ static constexpr const char *kAwsLogStreamNames = "aws.log.stream.names"; */ static constexpr const char *kAwsLogStreamArns = "aws.log.stream.arns"; +/** + * Time and date the release was created + */ +static constexpr const char *kHerokuReleaseCreationTimestamp = "heroku.release.creation_timestamp"; + +/** + * Commit hash for the current release + */ +static constexpr const char *kHerokuReleaseCommit = "heroku.release.commit"; + +/** + * Unique identifier for the application + */ +static constexpr const char *kHerokuAppId = "heroku.app.id"; + /** * Container name used by container runtime. */ @@ -295,35 +330,11 @@ providers/products:
  • Azure: The full name {@code +the {@code cloud.resource_id} attribute).
  • */ static constexpr const char *kFaasName = "faas.name"; -/** - * The unique ID of the single function that this runtime instance executes. - * - *

    Notes: -

    • On some cloud providers, it may not be possible to determine the full ID at startup, -so consider setting {@code faas.id} as a span attribute instead.
    • The exact value to use for -{@code faas.id} depends on the cloud provider:
    • AWS Lambda: The function ARN. Take care -not to use the "invoked ARN" directly but replace any alias suffix with -the resolved function version, as the same runtime instance may be invokable with multiple different -aliases.
    • GCP: The URI of the resource
    • -
    • Azure: The Fully Qualified -Resource ID of the invoked function, not the function app, having the form -{@code -/subscriptions//resourceGroups//providers/Microsoft.Web/sites//functions/}. -This means that a span attribute MUST be used, as an Azure function app can host multiple functions -that would usually share a TracerProvider.
    • -
    - */ -static constexpr const char *kFaasId = "faas.id"; - /** * The immutable version of the function being executed. * @@ -352,19 +363,20 @@ static constexpr const char *kFaasVersion = "faas.version"; static constexpr const char *kFaasInstance = "faas.instance"; /** - * The amount of memory available to the serverless function in MiB. + * The amount of memory available to the serverless function converted to Bytes. * *

    Notes:

    • It's recommended to set this attribute since e.g. too little memory can easily stop a Java AWS Lambda function from working correctly. On AWS Lambda, the environment variable {@code - AWS_LAMBDA_FUNCTION_MEMORY_SIZE} provides this information.
    + AWS_LAMBDA_FUNCTION_MEMORY_SIZE} provides this information (which must be multiplied by + 1,048,576). */ static constexpr const char *kFaasMaxMemory = "faas.max_memory"; /** * Unique host ID. For Cloud, this must be the instance_id assigned by the cloud provider. For - * non-containerized Linux systems, the {@code machine-id} located in {@code /etc/machine-id} or - * {@code /var/lib/dbus/machine-id} may be used. + * non-containerized systems, this should be the {@code machine-id}. See the table below for the + * sources to use to determine the {@code machine-id} based on operating system. */ static constexpr const char *kHostId = "host.id"; @@ -703,6 +715,8 @@ static constexpr const char *kAws = "aws"; static constexpr const char *kAzure = "azure"; /** Google Cloud Platform. */ static constexpr const char *kGcp = "gcp"; +/** Heroku Platform as a Service. */ +static constexpr const char *kHeroku = "heroku"; /** IBM Cloud. */ static constexpr const char *kIbmCloud = "ibm_cloud"; /** Tencent Cloud. */ @@ -754,7 +768,7 @@ static constexpr const char *kGcpCloudFunctions = "gcp_cloud_functions"; /** Google Cloud App Engine (GAE). */ static constexpr const char *kGcpAppEngine = "gcp_app_engine"; /** Red Hat OpenShift on Google Cloud. */ -static constexpr const char *kGoogleCloudOpenshift = "google_cloud_openshift"; +static constexpr const char *kGcpOpenshift = "gcp_openshift"; /** Red Hat OpenShift on IBM Cloud. */ static constexpr const char *kIbmCloudOpenshift = "ibm_cloud_openshift"; /** Tencent Cloud Cloud Virtual Machine (CVM). */ diff --git a/sdk/include/opentelemetry/sdk/trace/batch_span_processor.h b/sdk/include/opentelemetry/sdk/trace/batch_span_processor.h index 309d849bc7..60e93d8a9f 100644 --- a/sdk/include/opentelemetry/sdk/trace/batch_span_processor.h +++ b/sdk/include/opentelemetry/sdk/trace/batch_span_processor.h @@ -115,6 +115,7 @@ class BatchSpanProcessor : public SpanProcessor std::atomic is_force_wakeup_background_worker; std::atomic is_force_flush_pending; std::atomic is_force_flush_notified; + std::atomic force_flush_timeout_us; std::atomic is_shutdown; }; @@ -126,6 +127,7 @@ class BatchSpanProcessor : public SpanProcessor * @param synchronization_data Synchronization data to be notified. */ static void NotifyCompletion(bool notify_force_flush, + const std::unique_ptr &exporter, const std::shared_ptr &synchronization_data); void GetWaitAdjustedTime(std::chrono::microseconds &timeout, diff --git a/sdk/include/opentelemetry/sdk/trace/batch_span_processor_factory.h b/sdk/include/opentelemetry/sdk/trace/batch_span_processor_factory.h index 67f45917cf..6e66d2d2b9 100644 --- a/sdk/include/opentelemetry/sdk/trace/batch_span_processor_factory.h +++ b/sdk/include/opentelemetry/sdk/trace/batch_span_processor_factory.h @@ -19,7 +19,7 @@ namespace trace /** * Factory class for BatchSpanProcessor. */ -class BatchSpanProcessorFactory +class OPENTELEMETRY_EXPORT BatchSpanProcessorFactory { public: /** diff --git a/sdk/include/opentelemetry/sdk/trace/exporter.h b/sdk/include/opentelemetry/sdk/trace/exporter.h index 5826b5f454..ffacca2b35 100644 --- a/sdk/include/opentelemetry/sdk/trace/exporter.h +++ b/sdk/include/opentelemetry/sdk/trace/exporter.h @@ -17,10 +17,11 @@ namespace trace * SpanExporter defines the interface that protocol-specific span exporters must * implement. */ -class SpanExporter +class OPENTELEMETRY_EXPORT SpanExporter { public: - virtual ~SpanExporter() = default; + SpanExporter(); + virtual ~SpanExporter(); /** * Create a span recordable. This object will be used to record span data and @@ -42,6 +43,15 @@ class SpanExporter const nostd::span> &spans) noexcept = 0; + /** + * Export all spans that have been exported. + * @param timeout an optional timeout, the default timeout of 0 means that no + * timeout is applied. + * @return return true when all data are exported, and false when timeout + */ + virtual bool ForceFlush( + std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept; + /** * Shut down the exporter. * @param timeout an optional timeout. diff --git a/sdk/include/opentelemetry/sdk/trace/processor.h b/sdk/include/opentelemetry/sdk/trace/processor.h index 17ac0e59a0..f87b893837 100644 --- a/sdk/include/opentelemetry/sdk/trace/processor.h +++ b/sdk/include/opentelemetry/sdk/trace/processor.h @@ -18,7 +18,7 @@ namespace trace * Built-in span processors are responsible for batching and conversion of * spans to exportable representation and passing batches to exporters. */ -class SpanProcessor +class OPENTELEMETRY_EXPORT SpanProcessor { public: virtual ~SpanProcessor() = default; diff --git a/sdk/include/opentelemetry/sdk/trace/simple_processor.h b/sdk/include/opentelemetry/sdk/trace/simple_processor.h index 6796a10848..671218d0cf 100644 --- a/sdk/include/opentelemetry/sdk/trace/simple_processor.h +++ b/sdk/include/opentelemetry/sdk/trace/simple_processor.h @@ -55,7 +55,16 @@ class SimpleSpanProcessor : public SpanProcessor } } - bool ForceFlush(std::chrono::microseconds /* timeout */) noexcept override { return true; } + bool ForceFlush( + std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept override + { + if (exporter_ != nullptr) + { + return exporter_->ForceFlush(timeout); + } + + return true; + } bool Shutdown( std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept override diff --git a/sdk/include/opentelemetry/sdk/trace/simple_processor_factory.h b/sdk/include/opentelemetry/sdk/trace/simple_processor_factory.h index 152b64b90c..efa3078a38 100644 --- a/sdk/include/opentelemetry/sdk/trace/simple_processor_factory.h +++ b/sdk/include/opentelemetry/sdk/trace/simple_processor_factory.h @@ -17,7 +17,7 @@ namespace trace /** * Factory class for SimpleSpanProcessor. */ -class SimpleSpanProcessorFactory +class OPENTELEMETRY_EXPORT SimpleSpanProcessorFactory { public: /** diff --git a/sdk/include/opentelemetry/sdk/trace/tracer_context.h b/sdk/include/opentelemetry/sdk/trace/tracer_context.h index 572f60cafe..6dcdda8e01 100644 --- a/sdk/include/opentelemetry/sdk/trace/tracer_context.h +++ b/sdk/include/opentelemetry/sdk/trace/tracer_context.h @@ -40,6 +40,8 @@ class TracerContext std::unique_ptr id_generator = std::unique_ptr(new RandomIdGenerator())) noexcept; + virtual ~TracerContext() = default; + /** * Attaches a span processor to list of configured processors to this tracer context. * Processor once attached can't be removed. @@ -85,7 +87,7 @@ class TracerContext /** * Shutdown the span processor associated with this tracer provider. */ - bool Shutdown() noexcept; + 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. diff --git a/sdk/include/opentelemetry/sdk/trace/tracer_context_factory.h b/sdk/include/opentelemetry/sdk/trace/tracer_context_factory.h index eb88707328..b03ae297fc 100644 --- a/sdk/include/opentelemetry/sdk/trace/tracer_context_factory.h +++ b/sdk/include/opentelemetry/sdk/trace/tracer_context_factory.h @@ -17,7 +17,7 @@ namespace trace /** * Factory class for TracerContext. */ -class TracerContextFactory +class OPENTELEMETRY_EXPORT TracerContextFactory { public: /** diff --git a/sdk/include/opentelemetry/sdk/trace/tracer_provider_factory.h b/sdk/include/opentelemetry/sdk/trace/tracer_provider_factory.h index 0c493eb8e2..14458b2409 100644 --- a/sdk/include/opentelemetry/sdk/trace/tracer_provider_factory.h +++ b/sdk/include/opentelemetry/sdk/trace/tracer_provider_factory.h @@ -19,7 +19,7 @@ namespace trace * Factory class for TracerProvider. * See @ref TracerProvider. */ -class TracerProviderFactory +class OPENTELEMETRY_EXPORT TracerProviderFactory { public: /* Serie of builders with a single processor. */ diff --git a/sdk/include/opentelemetry/sdk/version/version.h b/sdk/include/opentelemetry/sdk/version/version.h index 2933dd7463..570d575c81 100644 --- a/sdk/include/opentelemetry/sdk/version/version.h +++ b/sdk/include/opentelemetry/sdk/version/version.h @@ -5,7 +5,7 @@ #include "opentelemetry/detail/preprocessor.h" -#define OPENTELEMETRY_SDK_VERSION "1.8.1" +#define OPENTELEMETRY_SDK_VERSION "1.9.0" #include "opentelemetry/version.h" @@ -14,17 +14,17 @@ 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; +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 *short_version; +extern const char *full_version; +extern const char *build_date; } // namespace version } // namespace sdk OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/src/CMakeLists.txt b/sdk/src/CMakeLists.txt index 5fe55165c9..9525b3f249 100644 --- a/sdk/src/CMakeLists.txt +++ b/sdk/src/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + add_subdirectory(common) add_subdirectory(trace) add_subdirectory(metrics) diff --git a/sdk/src/common/BUILD b/sdk/src/common/BUILD index b8369fc6f4..cdbd1955f3 100644 --- a/sdk/src/common/BUILD +++ b/sdk/src/common/BUILD @@ -1,16 +1,5 @@ -# 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. +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 package(default_visibility = ["//visibility:public"]) @@ -32,6 +21,18 @@ cc_library( ], ) +cc_library( + name = "env_variables", + srcs = [ + "env_variables.cc", + ], + deps = [ + "//api", + "//sdk:headers", + "//sdk/src/common:global_log_handler", + ], +) + cc_library( name = "global_log_handler", srcs = [ diff --git a/sdk/src/common/CMakeLists.txt b/sdk/src/common/CMakeLists.txt index d8674353b6..b23a93e80c 100644 --- a/sdk/src/common/CMakeLists.txt +++ b/sdk/src/common/CMakeLists.txt @@ -1,4 +1,7 @@ -set(COMMON_SRCS random.cc core.cc global_log_handler.cc) +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +set(COMMON_SRCS random.cc core.cc global_log_handler.cc env_variables.cc) if(WIN32) list(APPEND COMMON_SRCS platform/fork_windows.cc) else() @@ -13,9 +16,11 @@ 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}) +if(OPENTELEMETRY_INSTALL) + install( + TARGETS opentelemetry_common + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif() diff --git a/sdk/src/common/env_variables.cc b/sdk/src/common/env_variables.cc new file mode 100644 index 0000000000..a3f50b15ba --- /dev/null +++ b/sdk/src/common/env_variables.cc @@ -0,0 +1,196 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/sdk/common/env_variables.h" + +#ifdef _MSC_VER +# include +# define strcasecmp _stricmp +#else +# include +#endif + +#include + +#include "opentelemetry/sdk/common/global_log_handler.h" +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace common +{ + +bool GetRawEnvironmentVariable(const char *env_var_name, std::string &value) +{ +#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 endpoint_buffer; + if (required_size > 0) + { + endpoint_buffer = std::unique_ptr{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) + + if (endpoint_from_env != nullptr) + { + value = std::string{endpoint_from_env}; + return true; + } + + value = std::string{}; + return false; +#else + value = std::string{}; + return false; +#endif // !defined(NO_GETENV) +} + +bool GetBoolEnvironmentVariable(const char *env_var_name, bool &value) +{ + std::string raw_value; + bool exists = GetRawEnvironmentVariable(env_var_name, raw_value); + if (!exists || raw_value.empty()) + { + value = false; + return false; + } + + if (strcasecmp(raw_value.c_str(), "true") == 0) + { + value = true; + return true; + } + + if (strcasecmp(raw_value.c_str(), "false") == 0) + { + value = false; + return true; + } + + OTEL_INTERNAL_LOG_WARN("Environment variable <" << env_var_name << "> has an invalid value <" + << raw_value << ">, defaulting to false"); + value = false; + return true; +} + +static bool GetTimeoutFromString(const char *input, std::chrono::system_clock::duration &value) +{ + std::chrono::system_clock::duration::rep result = 0; + + // Skip spaces + for (; *input && (' ' == *input || '\t' == *input || '\r' == *input || '\n' == *input); ++input) + ; + + for (; *input && (*input >= '0' && *input <= '9'); ++input) + { + result = result * 10 + (*input - '0'); + } + + if (result == 0) + { + // Rejecting duration 0 as invalid. + return false; + } + + opentelemetry::nostd::string_view unit{input}; + + if (unit == "ns") + { + value = std::chrono::duration_cast( + std::chrono::nanoseconds{result}); + return true; + } + + if (unit == "us") + { + value = std::chrono::duration_cast( + std::chrono::microseconds{result}); + return true; + } + + if (unit == "ms") + { + value = std::chrono::duration_cast( + std::chrono::milliseconds{result}); + return true; + } + + if (unit == "s") + { + value = std::chrono::duration_cast( + std::chrono::seconds{result}); + return true; + } + + if (unit == "m") + { + value = std::chrono::duration_cast( + std::chrono::minutes{result}); + return true; + } + + if (unit == "h") + { + value = + std::chrono::duration_cast(std::chrono::hours{result}); + return true; + } + + if (unit == "") + { + // TODO: The spec says milliseconds, but opentelemetry-cpp implemented + // seconds by default. Fixing this is a breaking change. + + value = std::chrono::duration_cast( + std::chrono::seconds{result}); + return true; + } + + // Failed to parse the input string. + return false; +} + +bool GetDurationEnvironmentVariable(const char *env_var_name, + std::chrono::system_clock::duration &value) +{ + std::string raw_value; + bool exists = GetRawEnvironmentVariable(env_var_name, raw_value); + if (!exists || raw_value.empty()) + { + value = + std::chrono::duration_cast(std::chrono::seconds{0}); + return false; + } + + exists = GetTimeoutFromString(raw_value.c_str(), value); + + if (!exists) + { + OTEL_INTERNAL_LOG_WARN("Environment variable <" << env_var_name << "> has an invalid value <" + << raw_value << ">, ignoring"); + } + return exists; +} + +bool GetStringEnvironmentVariable(const char *env_var_name, std::string &value) +{ + bool exists = GetRawEnvironmentVariable(env_var_name, value); + if (!exists || value.empty()) + { + return false; + } + return true; +} + +} // namespace common +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/src/common/platform/BUILD b/sdk/src/common/platform/BUILD index c96a1417a0..f089ebf718 100644 --- a/sdk/src/common/platform/BUILD +++ b/sdk/src/common/platform/BUILD @@ -1,16 +1,5 @@ -# 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. +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 package(default_visibility = ["//visibility:public"]) diff --git a/sdk/src/logs/BUILD b/sdk/src/logs/BUILD index 53465cb8be..f1a0828527 100644 --- a/sdk/src/logs/BUILD +++ b/sdk/src/logs/BUILD @@ -1,16 +1,5 @@ -# 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. +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 package(default_visibility = ["//visibility:public"]) diff --git a/sdk/src/logs/CMakeLists.txt b/sdk/src/logs/CMakeLists.txt index ff43c4d92b..2b7db6eb7c 100644 --- a/sdk/src/logs/CMakeLists.txt +++ b/sdk/src/logs/CMakeLists.txt @@ -1,8 +1,15 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + add_library( opentelemetry_logs logger_provider.cc logger_provider_factory.cc logger.cc + exporter.cc + event_logger_provider.cc + event_logger_provider_factory.cc + event_logger.cc simple_log_record_processor.cc simple_log_record_processor_factory.cc batch_log_record_processor.cc @@ -24,9 +31,11 @@ target_include_directories( opentelemetry_logs PUBLIC "$") -install( - TARGETS opentelemetry_logs - EXPORT "${PROJECT_NAME}-target" - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +if(OPENTELEMETRY_INSTALL) + install( + TARGETS opentelemetry_logs + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif() diff --git a/sdk/src/logs/batch_log_record_processor.cc b/sdk/src/logs/batch_log_record_processor.cc index 7903c3b24c..6b1db1c666 100644 --- a/sdk/src/logs/batch_log_record_processor.cc +++ b/sdk/src/logs/batch_log_record_processor.cc @@ -46,6 +46,7 @@ BatchLogRecordProcessor::BatchLogRecordProcessor(std::unique_ptris_force_wakeup_background_worker.store(false); synchronization_data_->is_force_flush_pending.store(false); synchronization_data_->is_force_flush_notified.store(false); + synchronization_data_->force_flush_timeout_us.store(0); synchronization_data_->is_shutdown.store(false); } @@ -88,6 +89,7 @@ bool BatchLogRecordProcessor::ForceFlush(std::chrono::microseconds timeout) noex std::unique_lock lk_cv(synchronization_data_->force_flush_cv_m); synchronization_data_->is_force_flush_pending.store(true, std::memory_order_release); + synchronization_data_->force_flush_timeout_us.store(timeout.count(), std::memory_order_release); auto break_condition = [this]() { if (synchronization_data_->is_shutdown.load() == true) { @@ -106,23 +108,24 @@ bool BatchLogRecordProcessor::ForceFlush(std::chrono::microseconds timeout) noex // Fix timeout to meet requirement of wait_for timeout = opentelemetry::common::DurationUtil::AdjustWaitForTimeout( timeout, std::chrono::microseconds::zero()); - bool result; - if (timeout <= std::chrono::microseconds::zero()) + + std::chrono::steady_clock::duration timeout_steady = + std::chrono::duration_cast(timeout); + if (timeout_steady <= std::chrono::steady_clock::duration::zero()) { - bool wait_result = false; - while (!wait_result) - { - // When is_force_flush_notified.store(true) and force_flush_cv.notify_all() is called - // between is_force_flush_pending.load() and force_flush_cv.wait(). We must not wait - // for ever - wait_result = synchronization_data_->force_flush_cv.wait_for(lk_cv, scheduled_delay_millis_, - break_condition); - } - result = true; + timeout_steady = std::chrono::steady_clock::duration::max(); } - else + + bool result = false; + while (!result && timeout_steady > std::chrono::steady_clock::duration::zero()) { - result = synchronization_data_->force_flush_cv.wait_for(lk_cv, timeout, break_condition); + // When is_force_flush_notified.store(true) and force_flush_cv.notify_all() is called + // between is_force_flush_pending.load() and force_flush_cv.wait(). We must not wait + // for ever + std::chrono::steady_clock::time_point start_timepoint = std::chrono::steady_clock::now(); + result = synchronization_data_->force_flush_cv.wait_for(lk_cv, scheduled_delay_millis_, + break_condition); + timeout_steady -= std::chrono::steady_clock::now() - start_timepoint; } // If it's already signaled, we must wait util notified. @@ -202,7 +205,7 @@ void BatchLogRecordProcessor::Export() if (num_records_to_export == 0) { - NotifyCompletion(notify_force_flush, synchronization_data_); + NotifyCompletion(notify_force_flush, exporter_, synchronization_data_); break; } @@ -218,12 +221,13 @@ void BatchLogRecordProcessor::Export() exporter_->Export( nostd::span>(records_arr.data(), records_arr.size())); - NotifyCompletion(notify_force_flush, synchronization_data_); + NotifyCompletion(notify_force_flush, exporter_, synchronization_data_); } while (true); } void BatchLogRecordProcessor::NotifyCompletion( bool notify_force_flush, + const std::unique_ptr &exporter, const std::shared_ptr &synchronization_data) { if (!synchronization_data) @@ -233,6 +237,14 @@ void BatchLogRecordProcessor::NotifyCompletion( if (notify_force_flush) { + if (exporter) + { + std::chrono::microseconds timeout = opentelemetry::common::DurationUtil::AdjustWaitForTimeout( + std::chrono::microseconds{ + synchronization_data->force_flush_timeout_us.load(std::memory_order_acquire)}, + std::chrono::microseconds::zero()); + exporter->ForceFlush(timeout); + } synchronization_data->is_force_flush_notified.store(true, std::memory_order_release); synchronization_data->force_flush_cv.notify_one(); } diff --git a/sdk/src/logs/event_logger.cc b/sdk/src/logs/event_logger.cc new file mode 100644 index 0000000000..2106ecb233 --- /dev/null +++ b/sdk/src/logs/event_logger.cc @@ -0,0 +1,56 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifdef ENABLE_LOGS_PREVIEW +# include "opentelemetry/sdk/logs/event_logger.h" +# include "opentelemetry/sdk_config.h" +# include "opentelemetry/trace/provider.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace logs +{ +namespace nostd = opentelemetry::nostd; + +EventLogger::EventLogger(nostd::shared_ptr delegate_logger, + nostd::string_view event_domain) noexcept + : delegate_logger_(delegate_logger), event_domain_(event_domain) +{} + +const nostd::string_view EventLogger::GetName() noexcept +{ + if (delegate_logger_) + { + return delegate_logger_->GetName(); + } + + return {}; +} + +nostd::shared_ptr EventLogger::GetDelegateLogger() noexcept +{ + return delegate_logger_; +} + +void EventLogger::EmitEvent(nostd::string_view event_name, + nostd::unique_ptr &&log_record) noexcept +{ + if (!delegate_logger_ || !log_record) + { + return; + } + + if (!event_domain_.empty() && !event_name.empty()) + { + log_record->SetAttribute("event.domain", event_domain_); + log_record->SetAttribute("event.name", event_name); + } + + delegate_logger_->EmitLogRecord(std::move(log_record)); +} + +} // namespace logs +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/sdk/src/logs/event_logger_provider.cc b/sdk/src/logs/event_logger_provider.cc new file mode 100644 index 0000000000..2352fca59b --- /dev/null +++ b/sdk/src/logs/event_logger_provider.cc @@ -0,0 +1,41 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifdef ENABLE_LOGS_PREVIEW + +# include "opentelemetry/sdk/logs/event_logger_provider.h" +# include "opentelemetry/sdk/common/global_log_handler.h" +# include "opentelemetry/sdk/logs/event_logger.h" + +# include +# include +# include +# include +# include + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace logs +{ +namespace nostd = opentelemetry::nostd; + +EventLoggerProvider::EventLoggerProvider() noexcept +{ + OTEL_INTERNAL_LOG_DEBUG("[EventLoggerProvider] EventLoggerProvider created."); +} + +EventLoggerProvider::~EventLoggerProvider() {} + +nostd::shared_ptr EventLoggerProvider::CreateEventLogger( + nostd::shared_ptr delegate_logger, + nostd::string_view event_domain) noexcept +{ + return nostd::shared_ptr{ + new EventLogger(delegate_logger, event_domain)}; +} + +} // namespace logs +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/sdk/src/logs/event_logger_provider_factory.cc b/sdk/src/logs/event_logger_provider_factory.cc new file mode 100644 index 0000000000..966f33228a --- /dev/null +++ b/sdk/src/logs/event_logger_provider_factory.cc @@ -0,0 +1,24 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifdef ENABLE_LOGS_PREVIEW + +# include "opentelemetry/sdk/logs/event_logger_provider_factory.h" +# include "opentelemetry/sdk/logs/event_logger_provider.h" +# include "opentelemetry/sdk/resource/resource.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace logs +{ + +std::unique_ptr EventLoggerProviderFactory::Create() +{ + return std::unique_ptr(new EventLoggerProvider()); +} + +} // namespace logs +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/sdk/src/logs/exporter.cc b/sdk/src/logs/exporter.cc new file mode 100644 index 0000000000..20fdb6b25c --- /dev/null +++ b/sdk/src/logs/exporter.cc @@ -0,0 +1,27 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#ifdef ENABLE_LOGS_PREVIEW + +# include "opentelemetry/sdk/logs/exporter.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace logs +{ + +OPENTELEMETRY_EXPORT LogRecordExporter::LogRecordExporter() {} + +OPENTELEMETRY_EXPORT LogRecordExporter::~LogRecordExporter() {} + +OPENTELEMETRY_EXPORT bool LogRecordExporter::ForceFlush( + std::chrono::microseconds /*timeout*/) noexcept +{ + return true; +} + +} // namespace logs +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE +#endif diff --git a/sdk/src/logs/logger.cc b/sdk/src/logs/logger.cc index a955d7a1ae..190bfe6f5a 100644 --- a/sdk/src/logs/logger.cc +++ b/sdk/src/logs/logger.cc @@ -3,6 +3,7 @@ #ifdef ENABLE_LOGS_PREVIEW # include "opentelemetry/sdk/logs/logger.h" +# include "opentelemetry/context/runtime_context.h" # include "opentelemetry/sdk_config.h" # include "opentelemetry/trace/provider.h" @@ -15,13 +16,14 @@ namespace trace_api = opentelemetry::trace; namespace nostd = opentelemetry::nostd; namespace common = opentelemetry::common; -Logger::Logger( - nostd::string_view name, - std::shared_ptr context, - std::unique_ptr instrumentation_scope) noexcept +Logger::Logger(nostd::string_view name, + std::shared_ptr context, + std::unique_ptr instrumentation_scope, + bool include_trace_context) noexcept : logger_name_(std::string(name)), instrumentation_scope_(std::move(instrumentation_scope)), - context_(context) + context_(context), + include_trace_context_(include_trace_context) {} const nostd::string_view Logger::GetName() noexcept @@ -37,8 +39,41 @@ nostd::unique_ptr Logger::CreateLogRecord() noex return nullptr; } - return nostd::unique_ptr( - context_->GetProcessor().MakeRecordable().release()); + auto recordable = context_->GetProcessor().MakeRecordable(); + + recordable->SetObservedTimestamp(std::chrono::system_clock::now()); + + if (include_trace_context_ && + opentelemetry::context::RuntimeContext::GetCurrent().HasKey(opentelemetry::trace::kSpanKey)) + { + opentelemetry::context::ContextValue context_value = + opentelemetry::context::RuntimeContext::GetCurrent().GetValue( + opentelemetry::trace::kSpanKey); + if (nostd::holds_alternative>(context_value)) + { + nostd::shared_ptr &data = + nostd::get>(context_value); + if (data) + { + recordable->SetTraceId(data->GetContext().trace_id()); + recordable->SetTraceFlags(data->GetContext().trace_flags()); + recordable->SetSpanId(data->GetContext().span_id()); + } + } + else if (nostd::holds_alternative>(context_value)) + { + nostd::shared_ptr &data = + nostd::get>(context_value); + if (data) + { + recordable->SetTraceId(data->trace_id()); + recordable->SetTraceFlags(data->trace_flags()); + recordable->SetSpanId(data->span_id()); + } + } + } + + return nostd::unique_ptr(recordable.release()); } void Logger::EmitLogRecord(nostd::unique_ptr &&log_record) noexcept diff --git a/sdk/src/logs/logger_provider.cc b/sdk/src/logs/logger_provider.cc index 3000aa8230..2f75a09247 100644 --- a/sdk/src/logs/logger_provider.cc +++ b/sdk/src/logs/logger_provider.cc @@ -58,10 +58,11 @@ LoggerProvider::~LoggerProvider() nostd::shared_ptr 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 + nostd::string_view schema_url, + bool include_trace_context, + const opentelemetry::common::KeyValueIterable &attributes) noexcept { // Ensure only one thread can read/write from the map of loggers std::lock_guard lock_guard{lock_}; @@ -95,29 +96,19 @@ nostd::shared_ptr LoggerProvider::GetLogger( if (library_name.empty()) { lib = instrumentationscope::InstrumentationScope::Create(logger_name, library_version, - schema_url); + schema_url, attributes); } else { lib = instrumentationscope::InstrumentationScope::Create(library_name, library_version, - schema_url); + schema_url, attributes); } loggers_.push_back(std::shared_ptr( - new Logger(logger_name, context_, std::move(lib)))); + new Logger(logger_name, context_, std::move(lib), include_trace_context))); return nostd::shared_ptr{loggers_.back()}; } -nostd::shared_ptr LoggerProvider::GetLogger( - nostd::string_view logger_name, - nostd::span /* 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 processor) noexcept { context_->AddProcessor(std::move(processor)); diff --git a/sdk/src/logs/simple_log_record_processor.cc b/sdk/src/logs/simple_log_record_processor.cc index ef923bc590..50d4c20fdd 100644 --- a/sdk/src/logs/simple_log_record_processor.cc +++ b/sdk/src/logs/simple_log_record_processor.cc @@ -43,8 +43,12 @@ void SimpleLogRecordProcessor::OnEmit(std::unique_ptr &&record) noex /** * The simple processor does not have any log records to flush so this method is not used */ -bool SimpleLogRecordProcessor::ForceFlush(std::chrono::microseconds /* timeout */) noexcept +bool SimpleLogRecordProcessor::ForceFlush(std::chrono::microseconds timeout) noexcept { + if (exporter_ != nullptr) + { + return exporter_->ForceFlush(timeout); + } return true; } diff --git a/sdk/src/metrics/BUILD b/sdk/src/metrics/BUILD index e75ba6a1ac..c230f6a637 100644 --- a/sdk/src/metrics/BUILD +++ b/sdk/src/metrics/BUILD @@ -1,16 +1,5 @@ -# 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. +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 package(default_visibility = ["//visibility:public"]) diff --git a/sdk/src/metrics/CMakeLists.txt b/sdk/src/metrics/CMakeLists.txt index 7f9214e324..f53639332b 100644 --- a/sdk/src/metrics/CMakeLists.txt +++ b/sdk/src/metrics/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + add_library( opentelemetry_metrics async_instruments.cc @@ -26,9 +29,11 @@ target_include_directories( opentelemetry_metrics PUBLIC "$") -install( - TARGETS opentelemetry_metrics - EXPORT "${PROJECT_NAME}-target" - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +if(OPENTELEMETRY_INSTALL) + install( + TARGETS opentelemetry_metrics + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif() diff --git a/sdk/src/metrics/aggregation/histogram_aggregation.cc b/sdk/src/metrics/aggregation/histogram_aggregation.cc index 60dcc36827..fe01030f13 100644 --- a/sdk/src/metrics/aggregation/histogram_aggregation.cc +++ b/sdk/src/metrics/aggregation/histogram_aggregation.cc @@ -2,13 +2,14 @@ // SPDX-License-Identifier: Apache-2.0 #include "opentelemetry/sdk/metrics/aggregation/histogram_aggregation.h" +#include "opentelemetry/version.h" + #include #include #include #include -#include "opentelemetry/version.h" - #include + OPENTELEMETRY_BEGIN_NAMESPACE namespace sdk { @@ -59,16 +60,8 @@ void LongHistogramAggregation::Aggregate(int64_t value, point_data_.min_ = std::min(nostd::get(point_data_.min_), value); point_data_.max_ = std::max(nostd::get(point_data_.max_), value); } - size_t index = 0; - for (auto it = point_data_.boundaries_.begin(); it != point_data_.boundaries_.end(); ++it) - { - if (value < *it) - { - point_data_.counts_[index] += 1; - return; - } - index++; - } + size_t index = BucketBinarySearch(value, point_data_.boundaries_); + point_data_.counts_[index] += 1; } std::unique_ptr LongHistogramAggregation::Merge( @@ -77,7 +70,10 @@ std::unique_ptr LongHistogramAggregation::Merge( auto curr_value = nostd::get(ToPoint()); auto delta_value = nostd::get( (static_cast(delta).ToPoint())); - LongHistogramAggregation *aggr = new LongHistogramAggregation(); + HistogramAggregationConfig agg_config; + agg_config.boundaries_ = curr_value.boundaries_; + agg_config.record_min_max_ = record_min_max_; + LongHistogramAggregation *aggr = new LongHistogramAggregation(&agg_config); HistogramMerge(curr_value, delta_value, aggr->point_data_); return std::unique_ptr(aggr); } @@ -87,7 +83,10 @@ std::unique_ptr LongHistogramAggregation::Diff(const Aggregation &n auto curr_value = nostd::get(ToPoint()); auto next_value = nostd::get( (static_cast(next).ToPoint())); - LongHistogramAggregation *aggr = new LongHistogramAggregation(); + HistogramAggregationConfig agg_config; + agg_config.boundaries_ = curr_value.boundaries_; + agg_config.record_min_max_ = record_min_max_; + LongHistogramAggregation *aggr = new LongHistogramAggregation(&agg_config); HistogramDiff(curr_value, next_value, aggr->point_data_); return std::unique_ptr(aggr); } @@ -107,8 +106,8 @@ DoubleHistogramAggregation::DoubleHistogramAggregation(const AggregationConfig * } else { - point_data_.boundaries_ = - std::list{0.0, 5.0, 10.0, 25.0, 50.0, 75.0, 100.0, 250.0, 500.0, 1000.0}; + point_data_.boundaries_ = {0.0, 5.0, 10.0, 25.0, 50.0, 75.0, 100.0, 250.0, + 500.0, 750.0, 1000.0, 2500.0, 5000.0, 7500.0, 10000.0}; } if (ac) { @@ -141,16 +140,8 @@ void DoubleHistogramAggregation::Aggregate(double value, point_data_.min_ = std::min(nostd::get(point_data_.min_), value); point_data_.max_ = std::max(nostd::get(point_data_.max_), value); } - size_t index = 0; - for (auto it = point_data_.boundaries_.begin(); it != point_data_.boundaries_.end(); ++it) - { - if (value < *it) - { - point_data_.counts_[index] += 1; - return; - } - index++; - } + size_t index = BucketBinarySearch(value, point_data_.boundaries_); + point_data_.counts_[index] += 1; } std::unique_ptr DoubleHistogramAggregation::Merge( @@ -159,12 +150,10 @@ std::unique_ptr DoubleHistogramAggregation::Merge( auto curr_value = nostd::get(ToPoint()); auto delta_value = nostd::get( (static_cast(delta).ToPoint())); - std::shared_ptr aggregation_config(new HistogramAggregationConfig); - static_cast(aggregation_config.get()) - ->boundaries_ = curr_value.boundaries_; - static_cast(aggregation_config.get()) - ->record_min_max_ = record_min_max_; - DoubleHistogramAggregation *aggr = new DoubleHistogramAggregation(aggregation_config.get()); + HistogramAggregationConfig agg_config; + agg_config.boundaries_ = curr_value.boundaries_; + agg_config.record_min_max_ = record_min_max_; + DoubleHistogramAggregation *aggr = new DoubleHistogramAggregation(&agg_config); HistogramMerge(curr_value, delta_value, aggr->point_data_); return std::unique_ptr(aggr); } @@ -175,7 +164,10 @@ std::unique_ptr DoubleHistogramAggregation::Diff( auto curr_value = nostd::get(ToPoint()); auto next_value = nostd::get( (static_cast(next).ToPoint())); - DoubleHistogramAggregation *aggr = new DoubleHistogramAggregation(); + HistogramAggregationConfig agg_config; + agg_config.boundaries_ = curr_value.boundaries_; + agg_config.record_min_max_ = record_min_max_; + DoubleHistogramAggregation *aggr = new DoubleHistogramAggregation(&agg_config); HistogramDiff(curr_value, next_value, aggr->point_data_); return std::unique_ptr(aggr); } diff --git a/sdk/src/metrics/export/periodic_exporting_metric_reader.cc b/sdk/src/metrics/export/periodic_exporting_metric_reader.cc index 4220509b74..dfa4a5ee6b 100644 --- a/sdk/src/metrics/export/periodic_exporting_metric_reader.cc +++ b/sdk/src/metrics/export/periodic_exporting_metric_reader.cc @@ -6,7 +6,12 @@ #include "opentelemetry/sdk/metrics/push_metric_exporter.h" #include -#include +#if defined(_MSC_VER) +# pragma warning(suppress : 5204) +# include +#else +# include +#endif OPENTELEMETRY_BEGIN_NAMESPACE namespace sdk @@ -25,7 +30,7 @@ PeriodicExportingMetricReader::PeriodicExportingMetricReader( { OTEL_INTERNAL_LOG_WARN( "[Periodic Exporting Metric Reader] Invalid configuration: " - "export_interval_millis_ should be less than export_timeout_millis_, using default values"); + "export_timeout_millis_ should be less than export_interval_millis_, using default values"); export_interval_millis_ = kExportIntervalMillis; export_timeout_millis_ = kExportTimeOutMillis; } @@ -46,45 +51,140 @@ void PeriodicExportingMetricReader::DoBackgroundWork() std::unique_lock lk(cv_m_); do { - if (IsShutdown()) + auto start = std::chrono::steady_clock::now(); + auto status = CollectAndExportOnce(); + if (!status) { - break; + OTEL_INTERNAL_LOG_ERROR("[Periodic Exporting Metric Reader] Collect-Export Cycle Failure.") } - std::atomic 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); + auto end = std::chrono::steady_clock::now(); + auto export_time_ms = std::chrono::duration_cast(end - start); + auto remaining_wait_interval_ms = export_interval_millis_ - export_time_ms; + cv_.wait_for(lk, remaining_wait_interval_ms, [this]() { + if (is_force_wakeup_background_worker_.load(std::memory_order_acquire)) + { + is_force_wakeup_background_worker_.store(false, std::memory_order_release); return true; - }); + } + return IsShutdown(); }); - std::future_status status; - do - { - status = future_receive.wait_for(std::chrono::milliseconds(export_timeout_millis_)); - if (status == std::future_status::timeout) + } while (IsShutdown() != true); +} + +bool PeriodicExportingMetricReader::CollectAndExportOnce() +{ + std::atomic cancel_export_for_timeout{false}; + 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) { - cancel_export_for_timeout = true; - break; + OTEL_INTERNAL_LOG_ERROR( + "[Periodic Exporting Metric Reader] Collect took longer configured time: " + << export_timeout_millis_.count() << " ms, and timed out"); + return false; } - } while (status != std::future_status::ready); - auto end = std::chrono::steady_clock::now(); - auto export_time_ms = std::chrono::duration_cast(end - start); - auto remaining_wait_interval_ms = export_interval_millis_ - export_time_ms; - cv_.wait_for(lk, remaining_wait_interval_ms); - } while (true); + 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); + bool notify_force_flush = is_force_flush_pending_.exchange(false, std::memory_order_acq_rel); + if (notify_force_flush) + { + is_force_flush_notified_.store(true, std::memory_order_release); + force_flush_cv_.notify_one(); + } + + return true; } bool PeriodicExportingMetricReader::OnForceFlush(std::chrono::microseconds timeout) noexcept { - return exporter_->ForceFlush(timeout); + std::unique_lock lk_cv(force_flush_m_); + is_force_flush_pending_.store(true, std::memory_order_release); + auto break_condition = [this]() { + if (IsShutdown()) + { + return true; + } + + // Wake up the worker thread once. + if (is_force_flush_pending_.load(std::memory_order_acquire)) + { + is_force_wakeup_background_worker_.store(true, std::memory_order_release); + cv_.notify_one(); + } + return is_force_flush_notified_.load(std::memory_order_acquire); + }; + + auto wait_timeout = opentelemetry::common::DurationUtil::AdjustWaitForTimeout( + timeout, std::chrono::microseconds::zero()); + std::chrono::steady_clock::duration timeout_steady = + std::chrono::duration_cast(wait_timeout); + if (timeout_steady <= std::chrono::steady_clock::duration::zero()) + { + timeout_steady = std::chrono::steady_clock::duration::max(); + } + + bool result = false; + while (!result && timeout_steady > std::chrono::steady_clock::duration::zero()) + { + // When is_force_flush_notified_.store(true) and force_flush_cv_.notify_all() is called + // between is_force_flush_pending_.load() and force_flush_cv_.wait(). We must not wait + // for ever + std::chrono::steady_clock::time_point start_timepoint = std::chrono::steady_clock::now(); + result = force_flush_cv_.wait_for(lk_cv, export_interval_millis_, break_condition); + timeout_steady -= std::chrono::steady_clock::now() - start_timepoint; + } + + // If it will be already signaled, we must wait until notified. + // We use a spin lock here + if (false == is_force_flush_pending_.exchange(false, std::memory_order_acq_rel)) + { + for (int retry_waiting_times = 0; + false == is_force_flush_notified_.load(std::memory_order_acquire); ++retry_waiting_times) + { + opentelemetry::common::SpinLockMutex::fast_yield(); + if ((retry_waiting_times & 127) == 127) + { + std::this_thread::yield(); + } + } + } + is_force_flush_notified_.store(false, std::memory_order_release); + + if (result) + { + // - If original `timeout` is `zero`, use that in exporter::forceflush + // - Else if remaining `timeout_steady` more than zero, use that in exporter::forceflush + // - Else don't invoke exporter::forceflush ( as remaining time is zero or less) + if (timeout <= std::chrono::steady_clock::duration::zero()) + { + result = + exporter_->ForceFlush(std::chrono::duration_cast(timeout)); + } + else if (timeout_steady > std::chrono::steady_clock::duration::zero()) + { + result = exporter_->ForceFlush( + std::chrono::duration_cast(timeout_steady)); + } + else + { + // remaining timeout_steady is zero or less + result = false; + } + } + return result; } bool PeriodicExportingMetricReader::OnShutDown(std::chrono::microseconds timeout) noexcept diff --git a/sdk/src/metrics/instrument_metadata_validator.cc b/sdk/src/metrics/instrument_metadata_validator.cc index 50ee98e68a..4fde7d3f26 100644 --- a/sdk/src/metrics/instrument_metadata_validator.cc +++ b/sdk/src/metrics/instrument_metadata_validator.cc @@ -8,6 +8,10 @@ #include #include +#if defined(OPENTELEMETRY_HAVE_WORKING_REGEX) +# include +#endif + OPENTELEMETRY_BEGIN_NAMESPACE namespace sdk { @@ -20,7 +24,7 @@ const std::string kInstrumentUnitPattern = "[\x01-\x7F]{0,63}"; // instrument-unit = It can have a maximum length of 63 ASCII chars InstrumentMetaDataValidator::InstrumentMetaDataValidator() -#if HAVE_WORKING_REGEX +#if OPENTELEMETRY_HAVE_WORKING_REGEX // clang-format off : name_reg_key_{kInstrumentNamePattern}, unit_reg_key_{kInstrumentUnitPattern} @@ -31,7 +35,7 @@ InstrumentMetaDataValidator::InstrumentMetaDataValidator() bool InstrumentMetaDataValidator::ValidateName(nostd::string_view name) const { -#if HAVE_WORKING_REGEX +#if OPENTELEMETRY_HAVE_WORKING_REGEX return std::regex_match(name.data(), name_reg_key_); #else const size_t kMaxSize = 63; @@ -53,7 +57,7 @@ bool InstrumentMetaDataValidator::ValidateName(nostd::string_view name) const bool InstrumentMetaDataValidator::ValidateUnit(nostd::string_view unit) const { -#if HAVE_WORKING_REGEX +#if OPENTELEMETRY_HAVE_WORKING_REGEX return std::regex_match(unit.data(), unit_reg_key_); #else const size_t kMaxSize = 63; diff --git a/sdk/src/metrics/meter.cc b/sdk/src/metrics/meter.cc index 5c2f9b49f7..188e43d045 100644 --- a/sdk/src/metrics/meter.cc +++ b/sdk/src/metrics/meter.cc @@ -407,9 +407,8 @@ std::unique_ptr Meter::RegisterAsyncMetricStorage( { view_instr_desc.description_ = view.GetDescription(); } - auto storage = std::shared_ptr( - new AsyncMetricStorage(view_instr_desc, view.GetAggregationType(), - &view.GetAttributesProcessor(), view.GetAggregationConfig())); + auto storage = std::shared_ptr(new AsyncMetricStorage( + view_instr_desc, view.GetAggregationType(), view.GetAggregationConfig())); storage_registry_[instrument_descriptor.name_] = storage; static_cast(storages.get())->AddStorage(storage); return true; diff --git a/sdk/src/metrics/metric_reader.cc b/sdk/src/metrics/metric_reader.cc index 9ac7fc21ba..a778f0c41c 100644 --- a/sdk/src/metrics/metric_reader.cc +++ b/sdk/src/metrics/metric_reader.cc @@ -28,10 +28,12 @@ bool MetricReader::Collect( OTEL_INTERNAL_LOG_WARN( "MetricReader::Collect Cannot invoke Collect(). No MetricProducer registered for " "collection!") + return false; } if (IsShutdown()) { - OTEL_INTERNAL_LOG_WARN("MetricReader::Collect Cannot invoke Collect(). Shutdown in progress!"); + // Continue with warning, and let pull and push MetricReader state machine handle this. + OTEL_INTERNAL_LOG_WARN("MetricReader::Collect invoked while Shutdown in progress!"); } return metric_producer_->Collect(callback); diff --git a/sdk/src/metrics/state/metric_collector.cc b/sdk/src/metrics/state/metric_collector.cc index 86cda3eb5e..f0535a905d 100644 --- a/sdk/src/metrics/state/metric_collector.cc +++ b/sdk/src/metrics/state/metric_collector.cc @@ -40,13 +40,13 @@ bool MetricCollector::Collect( ResourceMetrics resource_metrics; meter_context_->ForEachMeter([&](std::shared_ptr meter) noexcept { auto collection_ts = std::chrono::system_clock::now(); - auto metric_data = meter->Collect(this, collection_ts); - if (!metric_data.empty ()) + auto metric_data = meter->Collect(this, collection_ts); + if (!metric_data.empty()) { ScopeMetrics scope_metrics; - scope_metrics.metric_data_ = std::move (metric_data); + scope_metrics.metric_data_ = std::move(metric_data); scope_metrics.scope_ = meter->GetInstrumentationScope(); - resource_metrics.scope_metric_data_.emplace_back(std::move (scope_metrics)); + resource_metrics.scope_metric_data_.emplace_back(std::move(scope_metrics)); } return true; }); diff --git a/sdk/src/metrics/state/temporal_metric_storage.cc b/sdk/src/metrics/state/temporal_metric_storage.cc index 95181e99c1..b6504a475b 100644 --- a/sdk/src/metrics/state/temporal_metric_storage.cc +++ b/sdk/src/metrics/state/temporal_metric_storage.cc @@ -17,8 +17,11 @@ namespace metrics { TemporalMetricStorage::TemporalMetricStorage(InstrumentDescriptor instrument_descriptor, + AggregationType aggregation_type, const AggregationConfig *aggregation_config) - : instrument_descriptor_(instrument_descriptor), aggregation_config_(aggregation_config) + : instrument_descriptor_(instrument_descriptor), + aggregation_type_(aggregation_type), + aggregation_config_(aggregation_config) {} bool TemporalMetricStorage::buildMetrics(CollectorHandle *collector, @@ -57,16 +60,19 @@ bool TemporalMetricStorage::buildMetrics(CollectorHandle *collector, { agg_hashmap->GetAllEnteries( [&merged_metrics, this](const MetricAttributes &attributes, Aggregation &aggregation) { - auto agg = merged_metrics->Get(attributes); + auto hash = opentelemetry::sdk::common::GetHashForAttributeMap(attributes); + auto agg = merged_metrics->Get(hash); if (agg) { - merged_metrics->Set(attributes, agg->Merge(aggregation)); + merged_metrics->Set(attributes, agg->Merge(aggregation), hash); } else { - merged_metrics->Set(attributes, DefaultAggregation::CreateAggregation( - instrument_descriptor_, aggregation_config_) - ->Merge(aggregation)); + merged_metrics->Set(attributes, + DefaultAggregation::CreateAggregation( + aggregation_type_, instrument_descriptor_, aggregation_config_) + ->Merge(aggregation), + hash); } return true; }); @@ -83,26 +89,30 @@ bool TemporalMetricStorage::buildMetrics(CollectorHandle *collector, 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 - { - auto def_agg = - DefaultAggregation::CreateAggregation(instrument_descriptor_, aggregation_config_); - merged_metrics->Set(attributes, def_agg->Merge(aggregation)); - } - return true; - }); + last_aggr_hashmap->GetAllEnteries( + [&merged_metrics, this](const MetricAttributes &attributes, Aggregation &aggregation) { + auto hash = opentelemetry::sdk::common::GetHashForAttributeMap(attributes); + auto agg = merged_metrics->Get(hash); + if (agg) + { + merged_metrics->Set(attributes, agg->Merge(aggregation), hash); + } + else + { + auto def_agg = DefaultAggregation::CreateAggregation( + aggregation_type_, instrument_descriptor_, aggregation_config_); + merged_metrics->Set(attributes, def_agg->Merge(aggregation), hash); + } + return true; + }); + } + else + { + last_collection_ts = last_reported_metrics_[collector].collection_ts; } last_reported_metrics_[collector] = LastReportedMetrics{std::move(merged_metrics), collection_ts}; @@ -132,7 +142,7 @@ bool TemporalMetricStorage::buildMetrics(CollectorHandle *collector, PointDataAttributes point_data_attr; point_data_attr.point_data = aggregation.ToPoint(); point_data_attr.attributes = attributes; - metric_data.point_data_attr_.emplace_back(std::move (point_data_attr)); + metric_data.point_data_attr_.emplace_back(std::move(point_data_attr)); return true; }); return callback(metric_data); diff --git a/sdk/src/resource/BUILD b/sdk/src/resource/BUILD index e42948b7eb..6cff52723a 100644 --- a/sdk/src/resource/BUILD +++ b/sdk/src/resource/BUILD @@ -1,16 +1,5 @@ -# 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. +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 package(default_visibility = ["//visibility:public"]) @@ -22,5 +11,6 @@ cc_library( deps = [ "//api", "//sdk:headers", + "//sdk/src/common:env_variables", ], ) diff --git a/sdk/src/resource/CMakeLists.txt b/sdk/src/resource/CMakeLists.txt index f8e8267dc2..f39b6f2a8f 100644 --- a/sdk/src/resource/CMakeLists.txt +++ b/sdk/src/resource/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + add_library(opentelemetry_resources resource.cc resource_detector.cc) set_target_properties(opentelemetry_resources PROPERTIES EXPORT_NAME resources) @@ -8,9 +11,11 @@ target_include_directories( opentelemetry_resources PUBLIC "$") -install( - TARGETS opentelemetry_resources - EXPORT "${PROJECT_NAME}-target" - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +if(OPENTELEMETRY_INSTALL) + install( + TARGETS opentelemetry_resources + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif() diff --git a/sdk/src/resource/resource.cc b/sdk/src/resource/resource.cc index 410e7318b1..f71e17a8a7 100644 --- a/sdk/src/resource/resource.cc +++ b/sdk/src/resource/resource.cc @@ -17,11 +17,12 @@ Resource::Resource(const ResourceAttributes &attributes, const std::string &sche : attributes_(attributes), schema_url_(schema_url) {} -Resource Resource::Merge(const Resource &other) noexcept +Resource Resource::Merge(const Resource &other) const noexcept { ResourceAttributes merged_resource_attributes(other.attributes_); merged_resource_attributes.insert(attributes_.begin(), attributes_.end()); - return Resource(merged_resource_attributes, other.schema_url_); + return Resource(merged_resource_attributes, + other.schema_url_.empty() ? schema_url_ : other.schema_url_); } Resource Resource::Create(const ResourceAttributes &attributes, const std::string &schema_url) diff --git a/sdk/src/resource/resource_detector.cc b/sdk/src/resource/resource_detector.cc index c60056539b..f5c856f088 100644 --- a/sdk/src/resource/resource_detector.cc +++ b/sdk/src/resource/resource_detector.cc @@ -15,9 +15,12 @@ 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) + std::string attributes_str; + bool exists; + + exists = opentelemetry::sdk::common::GetStringEnvironmentVariable(OTEL_RESOURCE_ATTRIBUTES, + attributes_str); + if (!exists) { return Resource(); } diff --git a/sdk/src/trace/BUILD b/sdk/src/trace/BUILD index 362680b744..df99eb1520 100644 --- a/sdk/src/trace/BUILD +++ b/sdk/src/trace/BUILD @@ -1,16 +1,5 @@ -# 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. +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 package(default_visibility = ["//visibility:public"]) diff --git a/sdk/src/trace/CMakeLists.txt b/sdk/src/trace/CMakeLists.txt index d09c047f64..94c2059548 100644 --- a/sdk/src/trace/CMakeLists.txt +++ b/sdk/src/trace/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + add_library( opentelemetry_trace tracer_context.cc @@ -6,6 +9,7 @@ add_library( tracer_provider_factory.cc tracer.cc span.cc + exporter.cc batch_span_processor.cc batch_span_processor_factory.cc simple_processor_factory.cc @@ -27,9 +31,11 @@ target_include_directories( opentelemetry_trace PUBLIC "$") -install( - TARGETS opentelemetry_trace - EXPORT "${PROJECT_NAME}-target" - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +if(OPENTELEMETRY_INSTALL) + install( + TARGETS opentelemetry_trace + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif() diff --git a/sdk/src/trace/batch_span_processor.cc b/sdk/src/trace/batch_span_processor.cc index de6c457da7..da9f39f054 100644 --- a/sdk/src/trace/batch_span_processor.cc +++ b/sdk/src/trace/batch_span_processor.cc @@ -30,6 +30,7 @@ BatchSpanProcessor::BatchSpanProcessor(std::unique_ptr &&exporter, synchronization_data_->is_force_wakeup_background_worker.store(false); synchronization_data_->is_force_flush_pending.store(false); synchronization_data_->is_force_flush_notified.store(false); + synchronization_data_->force_flush_timeout_us.store(0); synchronization_data_->is_shutdown.store(false); } @@ -77,6 +78,7 @@ bool BatchSpanProcessor::ForceFlush(std::chrono::microseconds timeout) noexcept std::unique_lock lk_cv(synchronization_data_->force_flush_cv_m); synchronization_data_->is_force_flush_pending.store(true, std::memory_order_release); + synchronization_data_->force_flush_timeout_us.store(timeout.count(), std::memory_order_release); auto break_condition = [this]() { if (synchronization_data_->is_shutdown.load() == true) { @@ -97,23 +99,23 @@ bool BatchSpanProcessor::ForceFlush(std::chrono::microseconds timeout) noexcept // Fix timeout to meet requirement of wait_for timeout = opentelemetry::common::DurationUtil::AdjustWaitForTimeout( timeout, std::chrono::microseconds::zero()); - bool result; - if (timeout <= std::chrono::microseconds::zero()) + std::chrono::steady_clock::duration timeout_steady = + std::chrono::duration_cast(timeout); + if (timeout_steady <= std::chrono::steady_clock::duration::zero()) { - bool wait_result = false; - while (!wait_result) - { - // When is_force_flush_notified.store(true) and force_flush_cv.notify_all() is called - // between is_force_flush_pending.load() and force_flush_cv.wait(). We must not wait - // for ever - wait_result = synchronization_data_->force_flush_cv.wait_for(lk_cv, schedule_delay_millis_, - break_condition); - } - result = true; + timeout_steady = std::chrono::steady_clock::duration::max(); } - else + + bool result = false; + while (!result && timeout_steady > std::chrono::steady_clock::duration::zero()) { - result = synchronization_data_->force_flush_cv.wait_for(lk_cv, timeout, break_condition); + // When is_force_flush_notified.store(true) and force_flush_cv.notify_all() is called + // between is_force_flush_pending.load() and force_flush_cv.wait(). We must not wait + // for ever + std::chrono::steady_clock::time_point start_timepoint = std::chrono::steady_clock::now(); + result = synchronization_data_->force_flush_cv.wait_for(lk_cv, schedule_delay_millis_, + break_condition); + timeout_steady -= std::chrono::steady_clock::now() - start_timepoint; } // If it will be already signaled, we must wait util notified. @@ -192,7 +194,7 @@ void BatchSpanProcessor::Export() if (num_records_to_export == 0) { - NotifyCompletion(notify_force_flush, synchronization_data_); + NotifyCompletion(notify_force_flush, exporter_, synchronization_data_); break; } buffer_.Consume(num_records_to_export, @@ -206,12 +208,13 @@ void BatchSpanProcessor::Export() }); exporter_->Export(nostd::span>(spans_arr.data(), spans_arr.size())); - NotifyCompletion(notify_force_flush, synchronization_data_); + NotifyCompletion(notify_force_flush, exporter_, synchronization_data_); } while (true); } void BatchSpanProcessor::NotifyCompletion( bool notify_force_flush, + const std::unique_ptr &exporter, const std::shared_ptr &synchronization_data) { if (!synchronization_data) @@ -221,6 +224,15 @@ void BatchSpanProcessor::NotifyCompletion( if (notify_force_flush) { + if (exporter) + { + std::chrono::microseconds timeout = opentelemetry::common::DurationUtil::AdjustWaitForTimeout( + std::chrono::microseconds{ + synchronization_data->force_flush_timeout_us.load(std::memory_order_acquire)}, + std::chrono::microseconds::zero()); + exporter->ForceFlush(timeout); + } + synchronization_data->is_force_flush_notified.store(true, std::memory_order_release); synchronization_data->force_flush_cv.notify_one(); } diff --git a/sdk/src/trace/exporter.cc b/sdk/src/trace/exporter.cc new file mode 100644 index 0000000000..5984583ba5 --- /dev/null +++ b/sdk/src/trace/exporter.cc @@ -0,0 +1,23 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/sdk/trace/exporter.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace trace +{ + +OPENTELEMETRY_EXPORT SpanExporter::SpanExporter() {} + +OPENTELEMETRY_EXPORT SpanExporter::~SpanExporter() {} + +OPENTELEMETRY_EXPORT bool SpanExporter::ForceFlush(std::chrono::microseconds /*timeout*/) noexcept +{ + return true; +} + +} // namespace trace +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/src/trace/samplers/trace_id_ratio.cc b/sdk/src/trace/samplers/trace_id_ratio.cc index dc5091a907..f7bb67f150 100644 --- a/sdk/src/trace/samplers/trace_id_ratio.cc +++ b/sdk/src/trace/samplers/trace_id_ratio.cc @@ -1,17 +1,6 @@ -// Copyright 2020, Open Telemetry Authors +// Copyright The OpenTelemetry 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. +// SPDX-License-Identifier: Apache-2.0 #include "opentelemetry/sdk/trace/samplers/trace_id_ratio.h" diff --git a/sdk/src/trace/tracer.cc b/sdk/src/trace/tracer.cc index 74e16bdfe0..07fd36d5b7 100644 --- a/sdk/src/trace/tracer.cc +++ b/sdk/src/trace/tracer.cc @@ -104,12 +104,22 @@ nostd::shared_ptr Tracer::StartSpan( void Tracer::ForceFlushWithMicroseconds(uint64_t timeout) noexcept { - (void)timeout; + if (context_) + { + context_->ForceFlush( + std::chrono::microseconds{static_cast(timeout)}); + } } void Tracer::CloseWithMicroseconds(uint64_t timeout) noexcept { - (void)timeout; + // Trace context is shared by many tracers.So we just call ForceFlush to flush all pending spans + // and do not shutdown it. + if (context_) + { + context_->ForceFlush( + std::chrono::microseconds{static_cast(timeout)}); + } } } // namespace trace } // namespace sdk diff --git a/sdk/src/trace/tracer_context.cc b/sdk/src/trace/tracer_context.cc index d204218021..0b89c5cefb 100644 --- a/sdk/src/trace/tracer_context.cc +++ b/sdk/src/trace/tracer_context.cc @@ -53,9 +53,9 @@ bool TracerContext::ForceFlush(std::chrono::microseconds timeout) noexcept return processor_->ForceFlush(timeout); } -bool TracerContext::Shutdown() noexcept +bool TracerContext::Shutdown(std::chrono::microseconds timeout) noexcept { - return processor_->Shutdown(); + return processor_->Shutdown(timeout); } } // namespace trace diff --git a/sdk/src/version/CMakeLists.txt b/sdk/src/version/CMakeLists.txt index 59231070b9..d8c48ed96d 100644 --- a/sdk/src/version/CMakeLists.txt +++ b/sdk/src/version/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + add_library(opentelemetry_version version.cc) set_target_properties(opentelemetry_version PROPERTIES EXPORT_NAME version) @@ -9,9 +12,11 @@ target_include_directories( opentelemetry_version PUBLIC "$") -install( - TARGETS opentelemetry_version - EXPORT "${PROJECT_NAME}-target" - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +if(OPENTELEMETRY_INSTALL) + install( + TARGETS opentelemetry_version + EXPORT "${PROJECT_NAME}-target" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif() diff --git a/sdk/src/version/version.cc b/sdk/src/version/version.cc index 829781222b..cd28813491 100644 --- a/sdk/src/version/version.cc +++ b/sdk/src/version/version.cc @@ -1,3 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + // Please DONOT touch this file. // Any changes done here would be overwritten by pre-commit git hook @@ -8,18 +11,18 @@ namespace sdk { namespace version { -const int MAJOR_VERSION = 1; -const int MINOR_VERSION = 8; -const int PATCH_VERSION = 1; -const char *PRE_RELEASE = "NONE"; -const char *BUILD_METADATA = "NONE"; -const int COUNT_NEW_COMMITS = 11; -const char *BRANCH = "pre_release_1.8.1"; -const char *COMMIT_HASH = "36ddf46ddea46a00d93aa647c821d7b6045ee42a"; -const char *SHORT_VERSION = "1.8.1"; -const char *FULL_VERSION = - "1.8.1-NONE-NONE-11-pre_release_1.8.1-36ddf46ddea46a00d93aa647c821d7b6045ee42a"; -const char *BUILD_DATE = "Sun 04 Dec 2022 10:11:53 AM UTC"; +const int major_version = 1; +const int minor_version = 9; +const int patch_version = 0; +const char *pre_release = "NONE"; +const char *build_metadata = "NONE"; +const int count_new_commits = 26; +const char *branch = "pre_release_1.9.0"; +const char *commit_hash = "a9876353337d5de74323b8935479618c9b422d09"; +const char *short_version = "1.9.0"; +const char *full_version = + "1.9.0-NONE-NONE-26-pre_release_1.9.0-a9876353337d5de74323b8935479618c9b422d09"; +const char *build_date = "Wed 12 Apr 2023 03:32:28 PM UTC"; } // namespace version } // namespace sdk OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/test/CMakeLists.txt b/sdk/test/CMakeLists.txt index 219455a7e7..5c2ce0d288 100644 --- a/sdk/test/CMakeLists.txt +++ b/sdk/test/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + add_subdirectory(common) add_subdirectory(trace) add_subdirectory(metrics) diff --git a/sdk/test/common/BUILD b/sdk/test/common/BUILD index 08ecb0bc8a..0f886ec569 100644 --- a/sdk/test/common/BUILD +++ b/sdk/test/common/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark") cc_test( @@ -160,3 +163,15 @@ otel_cc_benchmark( "//sdk:headers", ], ) + +cc_test( + name = "env_var_test", + srcs = [ + "env_var_test.cc", + ], + tags = ["test"], + deps = [ + "//sdk/src/common:env_variables", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/sdk/test/common/CMakeLists.txt b/sdk/test/common/CMakeLists.txt index a2a81ecc5a..0205061911 100644 --- a/sdk/test/common/CMakeLists.txt +++ b/sdk/test/common/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + foreach( testname random_test @@ -7,7 +10,8 @@ foreach( circular_buffer_test attribute_utils_test attributemap_hash_test - global_log_handle_test) + global_log_handle_test + env_var_test) add_executable(${testname} "${testname}.cc") target_link_libraries( diff --git a/sdk/test/common/attributemap_hash_test.cc b/sdk/test/common/attributemap_hash_test.cc index 49e53361ba..a7a893f2a8 100644 --- a/sdk/test/common/attributemap_hash_test.cc +++ b/sdk/test/common/attributemap_hash_test.cc @@ -19,6 +19,7 @@ TEST(AttributeMapHashTest, BasicTests) } { + // hash algo returns same value irrespective of order of attributes. OrderedAttributeMap map1 = {{"k1", 10}, {"k2", true}, {"k3", 12.22}}; OrderedAttributeMap map2 = {{"k3", 12.22}, {"k1", 10}, {"k2", true}}; EXPECT_TRUE(GetHashForAttributeMap(map1) == GetHashForAttributeMap(map2)); diff --git a/sdk/test/common/env_var_test.cc b/sdk/test/common/env_var_test.cc new file mode 100644 index 0000000000..23d3802361 --- /dev/null +++ b/sdk/test/common/env_var_test.cc @@ -0,0 +1,210 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/sdk/common/env_variables.h" + +#include + +#if defined(_MSC_VER) +using opentelemetry::sdk::common::setenv; +using opentelemetry::sdk::common::unsetenv; +#endif + +using opentelemetry::sdk::common::GetBoolEnvironmentVariable; +using opentelemetry::sdk::common::GetDurationEnvironmentVariable; +using opentelemetry::sdk::common::GetStringEnvironmentVariable; + +#ifndef NO_GETENV +TEST(EnvVarTest, BoolEnvVar) +{ + unsetenv("BOOL_ENV_VAR_NONE"); + setenv("BOOL_ENV_VAR_EMPTY", "", 1); + setenv("BOOL_ENV_VAR_T1", "true", 1); + setenv("BOOL_ENV_VAR_T2", "TRUE", 1); + setenv("BOOL_ENV_VAR_T3", "TrUe", 1); + setenv("BOOL_ENV_VAR_F1", "false", 1); + setenv("BOOL_ENV_VAR_F2", "FALSE", 1); + setenv("BOOL_ENV_VAR_F3", "FaLsE", 1); + setenv("BOOL_ENV_VAR_BROKEN", "Maybe ?", 1); + + bool exists; + bool value = true; + + exists = GetBoolEnvironmentVariable("BOOL_ENV_VAR_NONE", value); + EXPECT_FALSE(exists); + + value = true; + exists = GetBoolEnvironmentVariable("BOOL_ENV_VAR_EMPTY", value); + EXPECT_FALSE(exists); + EXPECT_FALSE(value); + + value = false; + exists = GetBoolEnvironmentVariable("BOOL_ENV_VAR_T1", value); + EXPECT_TRUE(exists); + EXPECT_TRUE(value); + + value = false; + exists = GetBoolEnvironmentVariable("BOOL_ENV_VAR_T2", value); + EXPECT_TRUE(exists); + EXPECT_TRUE(value); + + value = false; + exists = GetBoolEnvironmentVariable("BOOL_ENV_VAR_T3", value); + EXPECT_TRUE(exists); + EXPECT_TRUE(value); + + value = true; + exists = GetBoolEnvironmentVariable("BOOL_ENV_VAR_F1", value); + EXPECT_TRUE(exists); + EXPECT_FALSE(value); + + value = true; + exists = GetBoolEnvironmentVariable("BOOL_ENV_VAR_F2", value); + EXPECT_TRUE(exists); + EXPECT_FALSE(value); + + value = true; + exists = GetBoolEnvironmentVariable("BOOL_ENV_VAR_F3", value); + EXPECT_TRUE(exists); + EXPECT_FALSE(value); + + // This raises a warning, not verifying the warning text. + value = true; + exists = GetBoolEnvironmentVariable("BOOL_ENV_VAR_BROKEN", value); + EXPECT_TRUE(exists); + EXPECT_FALSE(value); + + unsetenv("BOOL_ENV_VAR_EMPTY"); + unsetenv("BOOL_ENV_VAR_T1"); + unsetenv("BOOL_ENV_VAR_T2"); + unsetenv("BOOL_ENV_VAR_T3"); + unsetenv("BOOL_ENV_VAR_F1"); + unsetenv("BOOL_ENV_VAR_F2"); + unsetenv("BOOL_ENV_VAR_F3"); + unsetenv("BOOL_ENV_VAR_BROKEN"); +} + +TEST(EnvVarTest, StringEnvVar) +{ + unsetenv("STRING_ENV_VAR_NONE"); + setenv("STRING_ENV_VAR_EMPTY", "", 1); + setenv("STRING_ENV_VAR", "my string", 1); + + bool exists; + std::string value; + + exists = GetStringEnvironmentVariable("STRING_ENV_VAR_NONE", value); + EXPECT_FALSE(exists); + + exists = GetStringEnvironmentVariable("STRING_ENV_VAR_EMPTY", value); + EXPECT_FALSE(exists); + EXPECT_EQ(value, ""); + + value = "poison"; + exists = GetStringEnvironmentVariable("STRING_ENV_VAR", value); + EXPECT_TRUE(exists); + EXPECT_EQ(value, "my string"); + + unsetenv("STRING_ENV_VAR_EMPTY"); + unsetenv("STRING_ENV_VAR"); +} + +TEST(EnvVarTest, DurationEnvVar) +{ + unsetenv("DURATION_ENV_VAR_NONE"); + setenv("DURATION_ENV_VAR_EMPTY", "", 1); + setenv("DURATION_ENV_VAR_1", "10ns", 1); + setenv("DURATION_ENV_VAR_2", "20us", 1); + setenv("DURATION_ENV_VAR_3", "30ms", 1); + setenv("DURATION_ENV_VAR_4", "40s", 1); + setenv("DURATION_ENV_VAR_5", "50m", 1); + setenv("DURATION_ENV_VAR_6", "60h", 1); + setenv("DURATION_ENV_VAR_7", "123", 1); + setenv("DURATION_ENV_VAR_BROKEN_1", "123 ms", 1); + setenv("DURATION_ENV_VAR_BROKEN_2", "1mississippi", 1); + + bool exists; + std::chrono::system_clock::duration poison; + std::chrono::system_clock::duration value; + std::chrono::system_clock::duration expected; + + poison = + std::chrono::duration_cast(std::chrono::seconds{666}); + + exists = GetDurationEnvironmentVariable("DURATION_ENV_VAR_NONE", value); + EXPECT_FALSE(exists); + + exists = GetDurationEnvironmentVariable("DURATION_ENV_VAR_EMPTY", value); + EXPECT_FALSE(exists); + + value = poison; + expected = + std::chrono::duration_cast(std::chrono::nanoseconds{10}); + exists = GetDurationEnvironmentVariable("DURATION_ENV_VAR_1", value); + EXPECT_TRUE(exists); + EXPECT_EQ(value, expected); + + value = poison; + expected = std::chrono::duration_cast( + std::chrono::microseconds{20}); + exists = GetDurationEnvironmentVariable("DURATION_ENV_VAR_2", value); + EXPECT_TRUE(exists); + EXPECT_EQ(value, expected); + + value = poison; + expected = std::chrono::duration_cast( + std::chrono::milliseconds{30}); + exists = GetDurationEnvironmentVariable("DURATION_ENV_VAR_3", value); + EXPECT_TRUE(exists); + EXPECT_EQ(value, expected); + + value = poison; + expected = + std::chrono::duration_cast(std::chrono::seconds{40}); + exists = GetDurationEnvironmentVariable("DURATION_ENV_VAR_4", value); + EXPECT_TRUE(exists); + EXPECT_EQ(value, expected); + + value = poison; + expected = + std::chrono::duration_cast(std::chrono::minutes{50}); + exists = GetDurationEnvironmentVariable("DURATION_ENV_VAR_5", value); + EXPECT_TRUE(exists); + EXPECT_EQ(value, expected); + + value = poison; + expected = + std::chrono::duration_cast(std::chrono::hours{60}); + exists = GetDurationEnvironmentVariable("DURATION_ENV_VAR_6", value); + EXPECT_TRUE(exists); + EXPECT_EQ(value, expected); + + value = poison; + // Deviation from the spec: 123 seconds instead of 123 milliseconds + expected = + std::chrono::duration_cast(std::chrono::seconds{123}); + exists = GetDurationEnvironmentVariable("DURATION_ENV_VAR_7", value); + EXPECT_TRUE(exists); + EXPECT_EQ(value, expected); + + // This raises a warning, not verifying the warning text. + exists = GetDurationEnvironmentVariable("DURATION_ENV_VAR_BROKEN_1", value); + EXPECT_FALSE(exists); + + // This raises a warning, not verifying the warning text. + exists = GetDurationEnvironmentVariable("DURATION_ENV_VAR_BROKEN_2", value); + EXPECT_FALSE(exists); + + unsetenv("STRING_ENV_VAR_EMPTY"); + unsetenv("STRING_ENV_VAR_1"); + unsetenv("STRING_ENV_VAR_2"); + unsetenv("STRING_ENV_VAR_3"); + unsetenv("STRING_ENV_VAR_4"); + unsetenv("STRING_ENV_VAR_5"); + unsetenv("STRING_ENV_VAR_6"); + unsetenv("STRING_ENV_VAR_7"); + unsetenv("STRING_ENV_VAR_BROKEN_1"); + unsetenv("STRING_ENV_VAR_BROKEN_2"); +} + +#endif diff --git a/sdk/test/instrumentationscope/BUILD b/sdk/test/instrumentationscope/BUILD index 0dd54ab648..39a61564a7 100644 --- a/sdk/test/instrumentationscope/BUILD +++ b/sdk/test/instrumentationscope/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + cc_test( name = "instrumentationscope_test", srcs = [ diff --git a/sdk/test/instrumentationscope/CMakeLists.txt b/sdk/test/instrumentationscope/CMakeLists.txt index c6de8b0e86..8fc1c991a8 100644 --- a/sdk/test/instrumentationscope/CMakeLists.txt +++ b/sdk/test/instrumentationscope/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + include(GoogleTest) foreach(testname instrumentationscope_test) diff --git a/sdk/test/instrumentationscope/instrumentationscope_test.cc b/sdk/test/instrumentationscope/instrumentationscope_test.cc index f5ddeaa35a..50800fd136 100644 --- a/sdk/test/instrumentationscope/instrumentationscope_test.cc +++ b/sdk/test/instrumentationscope/instrumentationscope_test.cc @@ -7,6 +7,7 @@ #include #include +#include #include using namespace opentelemetry; @@ -14,16 +15,176 @@ using namespace opentelemetry::sdk::instrumentationscope; TEST(InstrumentationScope, CreateInstrumentationScope) { + std::string library_name = "opentelemetry-cpp"; + std::string library_version = "0.1.0"; + std::string schema_url = "https://opentelemetry.io/schemas/1.2.0"; + uint32_t attrubite_value3[] = {7, 8, 9}; + auto instrumentation_scope = InstrumentationScope::Create( + library_name, library_version, schema_url, + {{"attribute-key1", "attribute-value"}, + {"attribute-key2", static_cast(123)}, + {"attribute-key3", opentelemetry::nostd::span(attrubite_value3)}}); + + EXPECT_EQ(instrumentation_scope->GetName(), library_name); + EXPECT_EQ(instrumentation_scope->GetVersion(), library_version); + EXPECT_EQ(instrumentation_scope->GetSchemaURL(), schema_url); + + auto attribute1 = instrumentation_scope->GetAttributes().find("attribute-key1"); + auto attribute2 = instrumentation_scope->GetAttributes().find("attribute-key2"); + auto attribute3 = instrumentation_scope->GetAttributes().find("attribute-key3"); + ASSERT_FALSE(attribute1 == instrumentation_scope->GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attribute1->second)); + EXPECT_EQ(opentelemetry::nostd::get(attribute1->second), "attribute-value"); + + ASSERT_FALSE(attribute2 == instrumentation_scope->GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attribute2->second)); + EXPECT_EQ(opentelemetry::nostd::get(attribute2->second), 123); + + ASSERT_FALSE(attribute3 == instrumentation_scope->GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative>(attribute3->second)); + + const std::vector &attribute3_values = + opentelemetry::nostd::get>(attribute3->second); + EXPECT_EQ(attribute3_values.size(), 3); + for (std::vector::size_type i = 0; i < 3; ++i) + { + EXPECT_EQ(attribute3_values[i], attrubite_value3[i]); + } +} + +TEST(InstrumentationScope, CreateInstrumentationScopeWithLoopForAttributes) +{ std::string library_name = "opentelemetry-cpp"; std::string library_version = "0.1.0"; std::string schema_url = "https://opentelemetry.io/schemas/1.2.0"; + uint32_t attrubite_value3[] = {7, 8, 9}; + + std::unordered_map attributes = { + {"attribute-key1", "attribute-value"}, + {"attribute-key2", static_cast(123)}, + {"attribute-key3", opentelemetry::nostd::span(attrubite_value3)}}; + + auto instrumentation_scope = + InstrumentationScope::Create(library_name, library_version, schema_url, attributes); + + EXPECT_EQ(instrumentation_scope->GetName(), library_name); + EXPECT_EQ(instrumentation_scope->GetVersion(), library_version); + EXPECT_EQ(instrumentation_scope->GetSchemaURL(), schema_url); + + auto attribute1 = instrumentation_scope->GetAttributes().find("attribute-key1"); + auto attribute2 = instrumentation_scope->GetAttributes().find("attribute-key2"); + auto attribute3 = instrumentation_scope->GetAttributes().find("attribute-key3"); + + ASSERT_FALSE(attribute1 == instrumentation_scope->GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attribute1->second)); + EXPECT_EQ(opentelemetry::nostd::get(attribute1->second), "attribute-value"); + + ASSERT_FALSE(attribute2 == instrumentation_scope->GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attribute2->second)); + EXPECT_EQ(opentelemetry::nostd::get(attribute2->second), 123); + + ASSERT_FALSE(attribute3 == instrumentation_scope->GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative>(attribute3->second)); + const std::vector &attribute3_values = + opentelemetry::nostd::get>(attribute3->second); + + EXPECT_EQ(attribute3_values.size(), 3); + for (std::vector::size_type i = 0; i < 3; ++i) + { + EXPECT_EQ(attribute3_values[i], attrubite_value3[i]); + } +} + +TEST(InstrumentationScope, CreateInstrumentationScopeWithKeyValueIterableAttributes) +{ + std::string library_name = "opentelemetry-cpp"; + std::string library_version = "0.1.0"; + std::string schema_url = "https://opentelemetry.io/schemas/1.2.0"; + uint32_t attrubite_value3[] = {7, 8, 9}; + + std::unordered_map attributes = { + {"attribute-key1", "attribute-value"}, + {"attribute-key2", static_cast(123)}, + {"attribute-key3", opentelemetry::nostd::span(attrubite_value3)}}; + + opentelemetry::common::KeyValueIterableView< + std::unordered_map> + attributes_view{attributes}; + + auto instrumentation_scope = + InstrumentationScope::Create(library_name, library_version, schema_url, attributes_view); + + EXPECT_EQ(instrumentation_scope->GetName(), library_name); + EXPECT_EQ(instrumentation_scope->GetVersion(), library_version); + EXPECT_EQ(instrumentation_scope->GetSchemaURL(), schema_url); + + auto attribute1 = instrumentation_scope->GetAttributes().find("attribute-key1"); + auto attribute2 = instrumentation_scope->GetAttributes().find("attribute-key2"); + auto attribute3 = instrumentation_scope->GetAttributes().find("attribute-key3"); + + ASSERT_FALSE(attribute1 == instrumentation_scope->GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attribute1->second)); + EXPECT_EQ(opentelemetry::nostd::get(attribute1->second), "attribute-value"); + + ASSERT_FALSE(attribute2 == instrumentation_scope->GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attribute2->second)); + EXPECT_EQ(opentelemetry::nostd::get(attribute2->second), 123); + + ASSERT_FALSE(attribute3 == instrumentation_scope->GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative>(attribute3->second)); + const std::vector &attribute3_values = + opentelemetry::nostd::get>(attribute3->second); + + EXPECT_EQ(attribute3_values.size(), 3); + for (std::vector::size_type i = 0; i < 3; ++i) + { + EXPECT_EQ(attribute3_values[i], attrubite_value3[i]); + } +} + +TEST(InstrumentationScope, SetAttribute) +{ + std::string library_name = "opentelemetry-cpp"; + std::string library_version = "0.1.0"; + std::string schema_url = "https://opentelemetry.io/schemas/1.2.0"; + uint32_t attrubite_value3[] = {7, 8, 9}; auto instrumentation_scope = InstrumentationScope::Create(library_name, library_version, schema_url); EXPECT_EQ(instrumentation_scope->GetName(), library_name); EXPECT_EQ(instrumentation_scope->GetVersion(), library_version); EXPECT_EQ(instrumentation_scope->GetSchemaURL(), schema_url); + EXPECT_EQ(instrumentation_scope->GetAttributes().size(), 0); + + instrumentation_scope->SetAttribute("attribute-key1", "attribute-value"); + instrumentation_scope->SetAttribute("attribute-key2", static_cast(123)); + instrumentation_scope->SetAttribute("attribute-key3", + opentelemetry::nostd::span(attrubite_value3)); + EXPECT_EQ(instrumentation_scope->GetAttributes().size(), 3); + + auto attribute1 = instrumentation_scope->GetAttributes().find("attribute-key1"); + auto attribute2 = instrumentation_scope->GetAttributes().find("attribute-key2"); + auto attribute3 = instrumentation_scope->GetAttributes().find("attribute-key3"); + + ASSERT_FALSE(attribute1 == instrumentation_scope->GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attribute1->second)); + EXPECT_EQ(opentelemetry::nostd::get(attribute1->second), "attribute-value"); + + ASSERT_FALSE(attribute2 == instrumentation_scope->GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attribute2->second)); + EXPECT_EQ(opentelemetry::nostd::get(attribute2->second), 123); + + ASSERT_FALSE(attribute3 == instrumentation_scope->GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative>(attribute3->second)); + + const std::vector &attribute3_values = + opentelemetry::nostd::get>(attribute3->second); + EXPECT_EQ(attribute3_values.size(), 3); + for (std::vector::size_type i = 0; i < 3; ++i) + { + EXPECT_EQ(attribute3_values[i], attrubite_value3[i]); + } } TEST(InstrumentationScope, LegacyInstrumentationLibrary) diff --git a/sdk/test/logs/BUILD b/sdk/test/logs/BUILD index edf3a9a8d3..2138a448f3 100644 --- a/sdk/test/logs/BUILD +++ b/sdk/test/logs/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + cc_test( name = "logger_provider_sdk_test", srcs = [ @@ -25,6 +28,7 @@ cc_test( ], deps = [ "//sdk/src/logs", + "//sdk/src/trace", "@com_google_googletest//:gtest_main", ], ) diff --git a/sdk/test/logs/CMakeLists.txt b/sdk/test/logs/CMakeLists.txt index 23d2a89f21..f38e32769f 100644 --- a/sdk/test/logs/CMakeLists.txt +++ b/sdk/test/logs/CMakeLists.txt @@ -1,9 +1,13 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + foreach(testname logger_provider_sdk_test logger_sdk_test log_record_test simple_log_record_processor_test batch_log_record_processor_test) add_executable(${testname} "${testname}.cc") - target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} opentelemetry_logs) + target_link_libraries( + ${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} + opentelemetry_logs opentelemetry_trace) gtest_add_tests( TARGET ${testname} TEST_PREFIX logs. diff --git a/sdk/test/logs/batch_log_record_processor_test.cc b/sdk/test/logs/batch_log_record_processor_test.cc index de3beb66fe..462e9b8397 100644 --- a/sdk/test/logs/batch_log_record_processor_test.cc +++ b/sdk/test/logs/batch_log_record_processor_test.cc @@ -70,10 +70,12 @@ class MockLogExporter final : public LogRecordExporter { public: MockLogExporter(std::shared_ptr>> logs_received, + std::shared_ptr> force_flush_counter, std::shared_ptr> is_shutdown, std::shared_ptr> is_export_completed, const std::chrono::milliseconds export_delay = std::chrono::milliseconds(0)) : logs_received_(logs_received), + force_flush_counter_(force_flush_counter), is_shutdown_(is_shutdown), is_export_completed_(is_export_completed), export_delay_(export_delay) @@ -109,6 +111,12 @@ class MockLogExporter final : public LogRecordExporter return ExportResult::kSuccess; } + bool ForceFlush(std::chrono::microseconds /* timeout */) noexcept override + { + ++(*force_flush_counter_); + return true; + } + // toggles the boolean flag marking this exporter as shut down bool Shutdown(std::chrono::microseconds /* timeout */) noexcept override { @@ -118,6 +126,7 @@ class MockLogExporter final : public LogRecordExporter private: std::shared_ptr>> logs_received_; + std::shared_ptr> force_flush_counter_; std::shared_ptr> is_shutdown_; std::shared_ptr> is_export_completed_; const std::chrono::milliseconds export_delay_; @@ -134,6 +143,7 @@ class BatchLogRecordProcessorTest : public testing::Test // ::testing::Test // is_shutdown flag, and the processor configuration options (default if unspecified) std::shared_ptr GetMockProcessor( std::shared_ptr>> logs_received, + std::shared_ptr> force_flush_counter, std::shared_ptr> is_shutdown, std::shared_ptr> is_export_completed = std::shared_ptr>(new std::atomic(false)), @@ -143,8 +153,8 @@ class BatchLogRecordProcessorTest : public testing::Test // ::testing::Test const size_t max_export_batch_size = 512) { return std::shared_ptr(new BatchLogRecordProcessor( - std::unique_ptr( - new MockLogExporter(logs_received, is_shutdown, is_export_completed, export_delay)), + std::unique_ptr(new MockLogExporter( + logs_received, force_flush_counter, is_shutdown, is_export_completed, export_delay)), max_queue_size, scheduled_delay_millis, max_export_batch_size)); } }; @@ -154,9 +164,10 @@ TEST_F(BatchLogRecordProcessorTest, TestShutdown) // initialize a batch log processor with the test exporter std::shared_ptr>> logs_received( new std::vector>); + std::shared_ptr> force_flush_counter(new std::atomic(0)); std::shared_ptr> is_shutdown(new std::atomic(false)); - auto batch_processor = GetMockProcessor(logs_received, is_shutdown); + auto batch_processor = GetMockProcessor(logs_received, force_flush_counter, is_shutdown); // Create a few test log records and send them to the processor const int num_logs = 3; @@ -189,11 +200,12 @@ TEST_F(BatchLogRecordProcessorTest, TestShutdown) TEST_F(BatchLogRecordProcessorTest, TestForceFlush) { + std::shared_ptr> force_flush_counter(new std::atomic(0)); std::shared_ptr> is_shutdown(new std::atomic(false)); std::shared_ptr>> logs_received( new std::vector>); - auto batch_processor = GetMockProcessor(logs_received, is_shutdown); + auto batch_processor = GetMockProcessor(logs_received, force_flush_counter, is_shutdown); const int num_logs = 2048; for (int i = 0; i < num_logs; ++i) @@ -204,6 +216,7 @@ TEST_F(BatchLogRecordProcessorTest, TestForceFlush) } EXPECT_TRUE(batch_processor->ForceFlush()); + EXPECT_GT(force_flush_counter->load(), 0); EXPECT_EQ(num_logs, logs_received->size()); for (int i = 0; i < num_logs; ++i) @@ -219,7 +232,9 @@ TEST_F(BatchLogRecordProcessorTest, TestForceFlush) batch_processor->OnEmit(std::move(log)); } + std::size_t force_flush_counter_before = force_flush_counter->load(); EXPECT_TRUE(batch_processor->ForceFlush()); + EXPECT_GT(force_flush_counter->load(), force_flush_counter_before); EXPECT_EQ(num_logs * 2, logs_received->size()); for (int i = 0; i < num_logs * 2; ++i) @@ -232,13 +247,14 @@ TEST_F(BatchLogRecordProcessorTest, TestManyLogsLoss) { /* Test that when exporting more than max_queue_size logs, some are most likely lost*/ + std::shared_ptr> force_flush_counter(new std::atomic(0)); std::shared_ptr> is_shutdown(new std::atomic(false)); std::shared_ptr>> logs_received( new std::vector>); const int max_queue_size = 4096; - auto batch_processor = GetMockProcessor(logs_received, is_shutdown); + auto batch_processor = GetMockProcessor(logs_received, force_flush_counter, is_shutdown); // Create max_queue_size log records for (int i = 0; i < max_queue_size; ++i) @@ -258,10 +274,11 @@ TEST_F(BatchLogRecordProcessorTest, TestManyLogsLossLess) { /* Test that no logs are lost when sending max_queue_size logs */ + std::shared_ptr> force_flush_counter(new std::atomic(0)); std::shared_ptr> is_shutdown(new std::atomic(false)); std::shared_ptr>> logs_received( new std::vector>); - auto batch_processor = GetMockProcessor(logs_received, is_shutdown); + auto batch_processor = GetMockProcessor(logs_received, force_flush_counter, is_shutdown); const int num_logs = 2048; @@ -286,6 +303,7 @@ TEST_F(BatchLogRecordProcessorTest, TestScheduledDelayMillis) /* Test that max_export_batch_size logs are exported every scheduled_delay_millis seconds */ + std::shared_ptr> force_flush_counter(new std::atomic(0)); std::shared_ptr> is_shutdown(new std::atomic(false)); std::shared_ptr> is_export_completed(new std::atomic(false)); std::shared_ptr>> logs_received( @@ -295,8 +313,9 @@ TEST_F(BatchLogRecordProcessorTest, TestScheduledDelayMillis) 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); + auto batch_processor = + GetMockProcessor(logs_received, force_flush_counter, is_shutdown, is_export_completed, + export_delay, scheduled_delay_millis); for (std::size_t i = 0; i < max_export_batch_size; ++i) { diff --git a/sdk/test/logs/logger_provider_sdk_test.cc b/sdk/test/logs/logger_provider_sdk_test.cc index 9339560377..cf993dc44c 100644 --- a/sdk/test/logs/logger_provider_sdk_test.cc +++ b/sdk/test/logs/logger_provider_sdk_test.cc @@ -4,9 +4,12 @@ #ifdef ENABLE_LOGS_PREVIEW # include +# include + # include "opentelemetry/logs/provider.h" # include "opentelemetry/nostd/shared_ptr.h" # include "opentelemetry/nostd/string_view.h" +# include "opentelemetry/sdk/logs/event_logger_provider_factory.h" # include "opentelemetry/sdk/logs/logger.h" # include "opentelemetry/sdk/logs/logger_provider.h" # include "opentelemetry/sdk/logs/recordable.h" @@ -33,8 +36,8 @@ TEST(LoggerProviderSDK, LoggerProviderGetLoggerSimple) auto lp = std::shared_ptr(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); + 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); @@ -54,7 +57,7 @@ TEST(LoggerProviderSDK, LoggerProviderGetLoggerSimple) 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); + auto logger3 = lp->GetLogger("logger1", "opentelelemtry_library", "", schema_url); ASSERT_EQ(logger1, logger3); auto sdk_logger3 = static_cast(logger3.get()); ASSERT_EQ(sdk_logger3->GetInstrumentationScope(), sdk_logger1->GetInstrumentationScope()); @@ -62,21 +65,51 @@ TEST(LoggerProviderSDK, LoggerProviderGetLoggerSimple) 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(new LoggerProvider()); nostd::string_view schema_url{"https://opentelemetry.io/schemas/1.11.0"}; - auto logger1 = lp->GetLogger("logger1", "", "opentelelemtry_library", "", schema_url); + auto logger1 = lp->GetLogger("logger1", "opentelelemtry_library", "", schema_url); - // Check GetLogger(logger_name, args) - std::array sv{"string"}; - nostd::span args{sv}; - auto logger2 = lp->GetLogger("logger2", args, "opentelelemtry_library", "", schema_url); + auto logger2 = lp->GetLogger("logger2", "opentelelemtry_library", "", schema_url); auto sdk_logger1 = static_cast(logger1.get()); auto sdk_logger2 = static_cast(logger2.get()); ASSERT_EQ(sdk_logger2->GetInstrumentationScope(), sdk_logger1->GetInstrumentationScope()); + + auto logger3 = lp->GetLogger("logger3", "opentelelemtry_library", "", schema_url, true, + {{"scope_key1", "scope_value"}, {"scope_key2", 2}}); + + auto sdk_logger3 = static_cast(logger3.get()); + EXPECT_EQ(sdk_logger3->GetInstrumentationScope().GetAttributes().size(), 2); + { + auto attibute = sdk_logger3->GetInstrumentationScope().GetAttributes().find("scope_key1"); + ASSERT_FALSE(attibute == sdk_logger3->GetInstrumentationScope().GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attibute->second)); + EXPECT_EQ(opentelemetry::nostd::get(attibute->second), "scope_value"); + } + + std::unordered_map scope_attributes = {{"scope_key", "scope_value"}}; + auto logger4 = + lp->GetLogger("logger4", "opentelelemtry_library", "", schema_url, true, scope_attributes); + auto sdk_logger4 = static_cast(logger4.get()); + + EXPECT_EQ(sdk_logger4->GetInstrumentationScope().GetAttributes().size(), 1); + { + auto attibute = sdk_logger4->GetInstrumentationScope().GetAttributes().find("scope_key"); + ASSERT_FALSE(attibute == sdk_logger4->GetInstrumentationScope().GetAttributes().end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attibute->second)); + EXPECT_EQ(opentelemetry::nostd::get(attibute->second), "scope_value"); + } +} + +TEST(LoggerProviderSDK, EventLoggerProviderFactory) +{ + auto elp = opentelemetry::sdk::logs::EventLoggerProviderFactory::Create(); + auto lp = std::shared_ptr(new LoggerProvider()); + + nostd::string_view schema_url{"https://opentelemetry.io/schemas/1.11.0"}; + auto logger1 = lp->GetLogger("logger1", "opentelelemtry_library", "", schema_url); + + auto event_logger = elp->CreateEventLogger(logger1, "otel-cpp.test"); } class DummyLogRecordable final : public opentelemetry::sdk::logs::Recordable diff --git a/sdk/test/logs/logger_sdk_test.cc b/sdk/test/logs/logger_sdk_test.cc index b6b597a887..5f6467cd91 100644 --- a/sdk/test/logs/logger_sdk_test.cc +++ b/sdk/test/logs/logger_sdk_test.cc @@ -3,12 +3,17 @@ #ifdef ENABLE_LOGS_PREVIEW +# include # include # include "opentelemetry/nostd/string_view.h" # include "opentelemetry/nostd/variant.h" +# include "opentelemetry/sdk/logs/event_logger.h" +# include "opentelemetry/sdk/logs/event_logger_provider.h" # include "opentelemetry/sdk/logs/logger.h" # include "opentelemetry/sdk/logs/recordable.h" +# include "opentelemetry/sdk/trace/tracer_provider_factory.h" +# include "opentelemetry/trace/scope.h" # include @@ -18,13 +23,13 @@ namespace nostd = opentelemetry::nostd; TEST(LoggerSDK, LogToNullProcessor) { - // Confirm Logger::Log() does not have undefined behavior + // Confirm Logger::EmitLogRecord() does not have undefined behavior // even when there is no processor set // since it calls Processor::OnEmit() auto lp = std::shared_ptr(new LoggerProvider()); const std::string schema_url{"https://opentelemetry.io/schemas/1.11.0"}; - auto logger = lp->GetLogger("logger", "", "opentelelemtry_library", "", schema_url); + auto logger = lp->GetLogger("logger", "opentelelemtry_library", "", schema_url); auto sdk_logger = static_cast(logger.get()); ASSERT_EQ(sdk_logger->GetInstrumentationScope().GetName(), "opentelelemtry_library"); @@ -39,7 +44,16 @@ class MockLogRecordable final : public opentelemetry::sdk::logs::Recordable public: void SetTimestamp(opentelemetry::common::SystemTimestamp) noexcept override {} - void SetObservedTimestamp(opentelemetry::common::SystemTimestamp) noexcept override {} + void SetObservedTimestamp( + opentelemetry::common::SystemTimestamp observed_timestamp) noexcept override + { + observed_timestamp_ = observed_timestamp; + } + + const opentelemetry::common::SystemTimestamp &GetObservedTimestamp() const noexcept + { + return observed_timestamp_; + } opentelemetry::logs::Severity GetSeverity() const noexcept { return severity_; } @@ -64,15 +78,50 @@ class MockLogRecordable final : public opentelemetry::sdk::logs::Recordable void SetBody(const std::string &message) noexcept { body_ = message; } - void SetTraceId(const opentelemetry::trace::TraceId &) noexcept override {} + void SetTraceId(const opentelemetry::trace::TraceId &trace_id) noexcept override + { + trace_id_ = trace_id; + } + inline const opentelemetry::trace::TraceId &GetTraceId() const noexcept { return trace_id_; } + + void SetSpanId(const opentelemetry::trace::SpanId &span_id) noexcept override + { + span_id_ = span_id; + } - void SetSpanId(const opentelemetry::trace::SpanId &) noexcept override {} + inline const opentelemetry::trace::SpanId &GetSpanId() const noexcept { return span_id_; } - void SetTraceFlags(const opentelemetry::trace::TraceFlags &) noexcept override {} + void SetTraceFlags(const opentelemetry::trace::TraceFlags &trace_flags) noexcept override + { + trace_flags_ = trace_flags; + } - void SetAttribute(nostd::string_view, - const opentelemetry::common::AttributeValue &) noexcept override - {} + inline const opentelemetry::trace::TraceFlags &GetTraceFlags() const noexcept + { + return trace_flags_; + } + + void SetAttribute(nostd::string_view key, + const opentelemetry::common::AttributeValue &value) noexcept override + { + if (!nostd::holds_alternative(value)) + { + return; + } + + if (key == "event.domain") + { + event_domain_ = static_cast(nostd::get(value)); + } + else if (key == "event.name") + { + event_name_ = static_cast(nostd::get(value)); + } + } + + inline const std::string &GetEventName() const noexcept { return event_name_; } + + inline const std::string &GetEventDomain() const noexcept { return event_domain_; } void SetResource(const opentelemetry::sdk::resource::Resource &) noexcept override {} @@ -80,9 +129,28 @@ class MockLogRecordable final : public opentelemetry::sdk::logs::Recordable const opentelemetry::sdk::instrumentationscope::InstrumentationScope &) noexcept override {} + void CopyFrom(const MockLogRecordable &other) + { + severity_ = other.severity_; + body_ = other.body_; + trace_id_ = other.trace_id_; + span_id_ = other.span_id_; + trace_flags_ = other.trace_flags_; + event_name_ = other.event_name_; + event_domain_ = other.event_domain_; + observed_timestamp_ = other.observed_timestamp_; + } + private: opentelemetry::logs::Severity severity_ = opentelemetry::logs::Severity::kInvalid; std::string body_; + opentelemetry::trace::TraceId trace_id_; + opentelemetry::trace::SpanId span_id_; + opentelemetry::trace::TraceFlags trace_flags_; + std::string event_name_; + std::string event_domain_; + opentelemetry::common::SystemTimestamp observed_timestamp_ = + std::chrono::system_clock::from_time_t(0); }; class MockProcessor final : public LogRecordProcessor @@ -111,8 +179,7 @@ class MockProcessor final : public LogRecordProcessor // 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()); + record_received_->CopyFrom(*copy); } bool ForceFlush(std::chrono::microseconds /* timeout */) noexcept override { return true; } @@ -124,15 +191,26 @@ TEST(LoggerSDK, LogToAProcessor) // Create an API LoggerProvider and logger auto api_lp = std::shared_ptr(new LoggerProvider()); const std::string schema_url{"https://opentelemetry.io/schemas/1.11.0"}; - auto logger = api_lp->GetLogger("logger", "", "opentelelemtry_library", "", schema_url); + auto logger = api_lp->GetLogger("logger", "opentelelemtry_library", "", schema_url, true); // 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(api_lp.get()); - auto logger2 = lp->GetLogger("logger", "", "opentelelemtry_library", "", schema_url); + auto logger2 = lp->GetLogger("logger", "opentelelemtry_library", "", schema_url, true); ASSERT_EQ(logger, logger2); + nostd::shared_ptr include_span; + { + std::vector> span_processors; + auto trace_provider = + opentelemetry::sdk::trace::TracerProviderFactory::Create(std::move(span_processors)); + include_span = trace_provider->GetTracer("logger")->StartSpan("test_logger"); + } + opentelemetry::trace::Scope trace_scope{include_span}; + + auto now = std::chrono::system_clock::now(); + auto sdk_logger = static_cast(logger.get()); ASSERT_EQ(sdk_logger->GetInstrumentationScope().GetName(), "opentelelemtry_library"); ASSERT_EQ(sdk_logger->GetInstrumentationScope().GetVersion(), ""); @@ -142,10 +220,60 @@ TEST(LoggerSDK, LogToAProcessor) lp->AddProcessor(std::unique_ptr( new MockProcessor(shared_recordable))); - // Check that the recordable created by the Log() statement is set properly - logger->Log(logs_api::Severity::kWarn, "Log Message"); + // Check that the recordable created by the EmitLogRecord() statement is set properly + logger->EmitLogRecord(logs_api::Severity::kWarn, "Log Message"); ASSERT_EQ(shared_recordable->GetSeverity(), logs_api::Severity::kWarn); ASSERT_EQ(shared_recordable->GetBody(), "Log Message"); + ASSERT_EQ(shared_recordable->GetTraceFlags().flags(), + include_span->GetContext().trace_flags().flags()); + char trace_id_in_logger[opentelemetry::trace::TraceId::kSize * 2]; + char trace_id_in_span[opentelemetry::trace::TraceId::kSize * 2]; + char span_id_in_logger[opentelemetry::trace::SpanId::kSize * 2]; + char span_id_in_span[opentelemetry::trace::SpanId::kSize * 2]; + shared_recordable->GetTraceId().ToLowerBase16(trace_id_in_logger); + include_span->GetContext().trace_id().ToLowerBase16(trace_id_in_span); + shared_recordable->GetSpanId().ToLowerBase16(span_id_in_logger); + include_span->GetContext().span_id().ToLowerBase16(span_id_in_span); + std::string trace_id_text_in_logger{trace_id_in_logger, sizeof(trace_id_in_logger)}; + std::string trace_id_text_in_span{trace_id_in_span, sizeof(trace_id_in_span)}; + std::string span_id_text_in_logger{span_id_in_logger, sizeof(span_id_in_logger)}; + std::string span_id_text_in_span{span_id_in_span, sizeof(span_id_in_span)}; + ASSERT_EQ(trace_id_text_in_logger, trace_id_text_in_span); + ASSERT_EQ(span_id_text_in_logger, span_id_text_in_span); + + ASSERT_GE( + static_cast(shared_recordable->GetObservedTimestamp()), + now); +} + +TEST(LoggerSDK, EventLog) +{ + // Create an API LoggerProvider and logger + auto api_lp = std::shared_ptr(new LoggerProvider()); + const std::string schema_url{"https://opentelemetry.io/schemas/1.11.0"}; + auto logger = api_lp->GetLogger("logger", "opentelelemtry_library", "", schema_url, false); + + auto api_elp = std::shared_ptr(new EventLoggerProvider()); + auto event_logger = api_elp->CreateEventLogger(logger, "otel-cpp.event_domain"); + + auto sdk_logger = static_cast(logger.get()); + ASSERT_EQ(sdk_logger->GetInstrumentationScope().GetName(), "opentelelemtry_library"); + ASSERT_EQ(sdk_logger->GetInstrumentationScope().GetVersion(), ""); + ASSERT_EQ(sdk_logger->GetInstrumentationScope().GetSchemaURL(), schema_url); + // Set a processor for the LoggerProvider + auto shared_recordable = std::shared_ptr(new MockLogRecordable()); + auto sdk_lp = static_cast(api_lp.get()); + sdk_lp->AddProcessor(std::unique_ptr( + new MockProcessor(shared_recordable))); + + // Check that the recordable created by the EmitEvent() statement is set properly + event_logger->EmitEvent("otel-cpp.event_name", logs_api::Severity::kWarn, "Event Log Message"); + + ASSERT_EQ(shared_recordable->GetSeverity(), logs_api::Severity::kWarn); + ASSERT_EQ(shared_recordable->GetBody(), "Event Log Message"); + ASSERT_EQ(shared_recordable->GetEventName(), "otel-cpp.event_name"); + ASSERT_EQ(shared_recordable->GetEventDomain(), "otel-cpp.event_domain"); } + #endif diff --git a/sdk/test/logs/simple_log_record_processor_test.cc b/sdk/test/logs/simple_log_record_processor_test.cc index 275991dc10..2d377cd924 100644 --- a/sdk/test/logs/simple_log_record_processor_test.cc +++ b/sdk/test/logs/simple_log_record_processor_test.cc @@ -69,10 +69,12 @@ class TestLogRecordable final : public opentelemetry::sdk::logs::Recordable class TestExporter final : public LogRecordExporter { public: - TestExporter(int *shutdown_counter, + TestExporter(int *force_flush_counter, + int *shutdown_counter, std::shared_ptr>> logs_received, size_t *batch_size_received) - : shutdown_counter_(shutdown_counter), + : force_flush_counter_(force_flush_counter), + shutdown_counter_(shutdown_counter), logs_received_(logs_received), batch_size_received(batch_size_received) {} @@ -99,14 +101,27 @@ class TestExporter final : public LogRecordExporter return ExportResult::kSuccess; } + bool ForceFlush(std::chrono::microseconds /* timeout */) noexcept override + { + if (nullptr != force_flush_counter_) + { + ++(*force_flush_counter_); + } + return true; + } + // Increment the shutdown counter everytime this method is called bool Shutdown(std::chrono::microseconds /* timeout */) noexcept override { - *shutdown_counter_ += 1; + if (nullptr != shutdown_counter_) + { + *shutdown_counter_ += 1; + } return true; } private: + int *force_flush_counter_; int *shutdown_counter_; std::shared_ptr>> logs_received_; size_t *batch_size_received; @@ -122,7 +137,7 @@ TEST(SimpleLogRecordProcessorTest, SendReceivedLogsToExporter) size_t batch_size_received = 0; std::unique_ptr exporter( - new TestExporter(nullptr, logs_received, &batch_size_received)); + new TestExporter(nullptr, nullptr, logs_received, &batch_size_received)); SimpleLogRecordProcessor processor(std::move(exporter)); @@ -152,7 +167,8 @@ TEST(SimpleLogRecordProcessorTest, ShutdownCalledOnce) // Create a TestExporter int num_shutdowns = 0; - std::unique_ptr exporter(new TestExporter(&num_shutdowns, nullptr, nullptr)); + std::unique_ptr exporter( + new TestExporter(nullptr, &num_shutdowns, nullptr, nullptr)); // Create a processor with the previous test exporter SimpleLogRecordProcessor processor(std::move(exporter)); @@ -167,11 +183,28 @@ TEST(SimpleLogRecordProcessorTest, ShutdownCalledOnce) EXPECT_EQ(1, num_shutdowns); } +TEST(SimpleLogRecordProcessorTest, ForceFlush) +{ + // Create a TestExporter + int num_force_flush = 0; + + std::unique_ptr exporter( + new TestExporter(&num_force_flush, nullptr, nullptr, nullptr)); + + // Create a processor with the previous test exporter + SimpleLogRecordProcessor processor(std::move(exporter)); + + // The first time processor shutdown is called + EXPECT_EQ(0, num_force_flush); + EXPECT_EQ(true, processor.ForceFlush()); + EXPECT_EQ(1, num_force_flush); +} + // A test exporter that always returns failure when shut down -class FailShutDownExporter final : public LogRecordExporter +class FailShutDownForceFlushExporter final : public LogRecordExporter { public: - FailShutDownExporter() {} + FailShutDownForceFlushExporter() {} std::unique_ptr MakeRecordable() noexcept override { @@ -184,16 +217,29 @@ class FailShutDownExporter final : public LogRecordExporter return ExportResult::kSuccess; } + bool ForceFlush(std::chrono::microseconds /* timeout */) noexcept override { return false; } + bool Shutdown(std::chrono::microseconds /* timeout */) noexcept override { return false; } }; // Tests for when when processor should fail to shutdown TEST(SimpleLogRecordProcessorTest, ShutDownFail) { - std::unique_ptr exporter(new FailShutDownExporter()); + std::unique_ptr exporter(new FailShutDownForceFlushExporter()); SimpleLogRecordProcessor processor(std::move(exporter)); // Expect failure result when exporter fails to shutdown EXPECT_EQ(false, processor.Shutdown()); } + +// Tests for when when processor should fail to force flush +TEST(SimpleLogRecordProcessorTest, ForceFlushFail) +{ + std::unique_ptr exporter(new FailShutDownForceFlushExporter()); + SimpleLogRecordProcessor processor(std::move(exporter)); + + // Expect failure result when exporter fails to force flush + EXPECT_EQ(false, processor.ForceFlush()); +} + #endif diff --git a/sdk/test/metrics/BUILD b/sdk/test/metrics/BUILD index 294510b571..d7ed9e5fb6 100644 --- a/sdk/test/metrics/BUILD +++ b/sdk/test/metrics/BUILD @@ -1,5 +1,23 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark") +cc_library( + name = "metrics_common_test_utils", + srcs = [ + "common.cc", + ], + hdrs = ["common.h"], + tags = [ + "metrics", + "test", + ], + deps = [ + "//sdk/src/metrics", + ], +) + cc_test( name = "meter_test", srcs = [ @@ -10,7 +28,7 @@ cc_test( "test", ], deps = [ - "//sdk/src/metrics", + "metrics_common_test_utils", "@com_google_googletest//:gtest_main", ], ) @@ -25,7 +43,7 @@ cc_test( "test", ], deps = [ - "//sdk/src/metrics", + "metrics_common_test_utils", "//sdk/src/resource", "@com_google_googletest//:gtest_main", ], @@ -41,7 +59,23 @@ cc_test( "test", ], deps = [ - "//sdk/src/metrics", + "metrics_common_test_utils", + "//sdk/src/resource", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "histogram_test", + srcs = [ + "histogram_test.cc", + ], + tags = [ + "metrics", + "test", + ], + deps = [ + "metrics_common_test_utils", "//sdk/src/resource", "@com_google_googletest//:gtest_main", ], @@ -57,7 +91,7 @@ cc_test( "test", ], deps = [ - "//sdk/src/metrics", + "metrics_common_test_utils", "//sdk/src/resource", "@com_google_googletest//:gtest_main", ], @@ -73,7 +107,7 @@ cc_test( "test", ], deps = [ - "//sdk/src/metrics", + "metrics_common_test_utils", "//sdk/src/resource", "@com_google_googletest//:gtest_main", ], @@ -89,7 +123,7 @@ cc_test( "test", ], deps = [ - "//sdk/src/metrics", + "metrics_common_test_utils", "//sdk/src/resource", "@com_google_googletest//:gtest_main", ], @@ -105,7 +139,7 @@ cc_test( "test", ], deps = [ - "//sdk/src/metrics", + "metrics_common_test_utils", "//sdk/src/resource", "@com_google_googletest//:gtest_main", ], @@ -121,7 +155,7 @@ cc_test( "test", ], deps = [ - "//sdk/src/metrics", + "metrics_common_test_utils", "//sdk/src/resource", "@com_google_googletest//:gtest_main", ], @@ -137,7 +171,7 @@ cc_test( "test", ], deps = [ - "//sdk/src/metrics", + "metrics_common_test_utils", "//sdk/src/resource", "@com_google_googletest//:gtest_main", ], @@ -153,7 +187,7 @@ cc_test( "test", ], deps = [ - "//sdk/src/metrics", + "metrics_common_test_utils", "@com_google_googletest//:gtest_main", ], ) @@ -168,7 +202,7 @@ cc_test( "test", ], deps = [ - "//sdk/src/metrics", + "metrics_common_test_utils", "//sdk/src/resource", "@com_google_googletest//:gtest_main", ], @@ -184,7 +218,7 @@ cc_test( "test", ], deps = [ - "//sdk/src/metrics", + "metrics_common_test_utils", "//sdk/src/resource", "@com_google_googletest//:gtest_main", ], @@ -200,7 +234,7 @@ cc_test( "test", ], deps = [ - "//sdk/src/metrics", + "metrics_common_test_utils", "//sdk/src/resource", "@com_google_googletest//:gtest_main", ], @@ -216,7 +250,7 @@ cc_test( "test", ], deps = [ - "//sdk/src/metrics", + "metrics_common_test_utils", "@com_google_googletest//:gtest_main", ], ) @@ -231,7 +265,37 @@ cc_test( "test", ], deps = [ - "//sdk/src/metrics", + "metrics_common_test_utils", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "histogram_aggregation_test", + srcs = [ + "histogram_aggregation_test.cc", + ], + tags = [ + "metrics", + "test", + ], + deps = [ + "metrics_common_test_utils", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "sum_aggregation_test", + srcs = [ + "sum_aggregation_test.cc", + ], + tags = [ + "metrics", + "test", + ], + deps = [ + "metrics_common_test_utils", "@com_google_googletest//:gtest_main", ], ) @@ -247,7 +311,7 @@ otel_cc_benchmark( "test", ], deps = [ - "//sdk/src/metrics", + "metrics_common_test_utils", ], ) @@ -262,6 +326,56 @@ otel_cc_benchmark( "test", ], deps = [ + "metrics_common_test_utils", + ], +) + +otel_cc_benchmark( + name = "histogram_aggregation_benchmark", + srcs = [ + "histogram_aggregation_benchmark.cc", + ], + tags = [ + "benchmark", + "metrics", + "test", + ], + deps = [ + "metrics_common_test_utils", "//sdk/src/metrics", + "//sdk/src/resource", + ], +) + +otel_cc_benchmark( + name = "sum_aggregation_benchmark", + srcs = [ + "sum_aggregation_benchmark.cc", + ], + tags = [ + "benchmark", + "metrics", + "test", + ], + deps = [ + "metrics_common_test_utils", + "//sdk/src/metrics", + "//sdk/src/resource", + ], +) + +otel_cc_benchmark( + name = "measurements_benchmark", + srcs = [ + "measurements_benchmark.cc", + ], + tags = [ + "benchmark", + "metrics", + "test", + ], + deps = [ + "//sdk/src/metrics", + "//sdk/src/resource", ], ) diff --git a/sdk/test/metrics/CMakeLists.txt b/sdk/test/metrics/CMakeLists.txt index 4205ce7338..fcaa026983 100644 --- a/sdk/test/metrics/CMakeLists.txt +++ b/sdk/test/metrics/CMakeLists.txt @@ -1,11 +1,20 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +add_library(metrics_common_test_utils common.cc) +target_link_libraries(metrics_common_test_utils opentelemetry_metrics) + foreach( testname meter_provider_sdk_test meter_test view_registry_test aggregation_test + sum_aggregation_test + histogram_aggregation_test attributes_processor_test attributes_hashmap_test + histogram_test sync_metric_storage_counter_test sync_metric_storage_histogram_test sync_metric_storage_gauge_test @@ -22,7 +31,7 @@ foreach( add_executable(${testname} "${testname}.cc") target_link_libraries( ${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} - opentelemetry_resources opentelemetry_metrics) + metrics_common_test_utils opentelemetry_resources) gtest_add_tests( TARGET ${testname} TEST_PREFIX metrics. @@ -38,6 +47,22 @@ if(WITH_BENCHMARK) add_executable(attributes_hashmap_benchmark attributes_hashmap_benchmark.cc) target_link_libraries(attributes_hashmap_benchmark benchmark::benchmark ${CMAKE_THREAD_LIBS_INIT} opentelemetry_common) + + add_executable(histogram_aggregation_benchmark + histogram_aggregation_benchmark.cc) + target_link_libraries( + histogram_aggregation_benchmark benchmark::benchmark + ${CMAKE_THREAD_LIBS_INIT} metrics_common_test_utils opentelemetry_common + opentelemetry_resources) + + add_executable(measurements_benchmark measurements_benchmark.cc) + target_link_libraries( + measurements_benchmark benchmark::benchmark opentelemetry_metrics + opentelemetry_resources ${CMAKE_THREAD_LIBS_INIT} opentelemetry_common) + add_executable(sum_aggregation_benchmark sum_aggregation_benchmark.cc) + target_link_libraries( + sum_aggregation_benchmark benchmark::benchmark ${CMAKE_THREAD_LIBS_INIT} + metrics_common_test_utils opentelemetry_common opentelemetry_resources) endif() add_subdirectory(exemplar) diff --git a/sdk/test/metrics/aggregation_test.cc b/sdk/test/metrics/aggregation_test.cc index fffe56b104..9f307cb015 100644 --- a/sdk/test/metrics/aggregation_test.cc +++ b/sdk/test/metrics/aggregation_test.cc @@ -76,17 +76,17 @@ TEST(Aggregation, LongHistogramAggregation) ASSERT_TRUE(nostd::holds_alternative(histogram_data.sum_)); EXPECT_EQ(nostd::get(histogram_data.sum_), 0); EXPECT_EQ(histogram_data.count_, 0); - aggr.Aggregate((int64_t)12, {}); // lies in fourth bucket - aggr.Aggregate((int64_t)100, {}); // lies in eight bucket + aggr.Aggregate((int64_t)12, {}); // lies in third bucket + aggr.Aggregate((int64_t)100, {}); // lies in sixth bucket histogram_data = nostd::get(aggr.ToPoint()); EXPECT_EQ(nostd::get(histogram_data.min_), 12); EXPECT_EQ(nostd::get(histogram_data.max_), 100); EXPECT_EQ(nostd::get(histogram_data.sum_), 112); EXPECT_EQ(histogram_data.count_, 2); EXPECT_EQ(histogram_data.counts_[3], 1); - EXPECT_EQ(histogram_data.counts_[7], 1); - aggr.Aggregate((int64_t)13, {}); // lies in fourth bucket - aggr.Aggregate((int64_t)252, {}); // lies in ninth bucket + EXPECT_EQ(histogram_data.counts_[6], 1); + aggr.Aggregate((int64_t)13, {}); // lies in third bucket + aggr.Aggregate((int64_t)252, {}); // lies in eight bucket histogram_data = nostd::get(aggr.ToPoint()); EXPECT_EQ(histogram_data.count_, 4); EXPECT_EQ(histogram_data.counts_[3], 2); @@ -132,9 +132,9 @@ TEST(Aggregation, LongHistogramAggregationBoundaries) { std::shared_ptr aggregation_config{ new opentelemetry::sdk::metrics::HistogramAggregationConfig}; - std::list user_boundaries = {0.0, 50.0, 100.0, 250.0, 500.0, - 750.0, 1000.0, 2500.0, 5000.0, 10000.0}; - aggregation_config->boundaries_ = user_boundaries; + std::vector user_boundaries = {0.0, 50.0, 100.0, 250.0, 500.0, + 750.0, 1000.0, 2500.0, 5000.0, 10000.0}; + aggregation_config->boundaries_ = user_boundaries; LongHistogramAggregation aggr{aggregation_config.get()}; auto data = aggr.ToPoint(); ASSERT_TRUE(nostd::holds_alternative(data)); @@ -146,9 +146,9 @@ TEST(Aggregation, DoubleHistogramAggregationBoundaries) { std::shared_ptr aggregation_config{ new opentelemetry::sdk::metrics::HistogramAggregationConfig}; - std::list user_boundaries = {0.0, 50.0, 100.0, 250.0, 500.0, - 750.0, 1000.0, 2500.0, 5000.0, 10000.0}; - aggregation_config->boundaries_ = user_boundaries; + std::vector user_boundaries = {0.0, 50.0, 100.0, 250.0, 500.0, + 750.0, 1000.0, 2500.0, 5000.0, 10000.0}; + aggregation_config->boundaries_ = user_boundaries; DoubleHistogramAggregation aggr{aggregation_config.get()}; auto data = aggr.ToPoint(); ASSERT_TRUE(nostd::holds_alternative(data)); @@ -165,17 +165,17 @@ TEST(Aggregation, DoubleHistogramAggregation) ASSERT_TRUE(nostd::holds_alternative(histogram_data.sum_)); EXPECT_EQ(nostd::get(histogram_data.sum_), 0); EXPECT_EQ(histogram_data.count_, 0); - aggr.Aggregate(12.0, {}); // lies in fourth bucket - aggr.Aggregate(100.0, {}); // lies in eight bucket + aggr.Aggregate(12.0, {}); // lies in third bucket + aggr.Aggregate(100.0, {}); // lies in sixth bucket histogram_data = nostd::get(aggr.ToPoint()); EXPECT_EQ(nostd::get(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_EQ(histogram_data.counts_[6], 1); EXPECT_EQ(nostd::get(histogram_data.min_), 12); EXPECT_EQ(nostd::get(histogram_data.max_), 100); - aggr.Aggregate(13.0, {}); // lies in fourth bucket - aggr.Aggregate(252.0, {}); // lies in ninth bucket + aggr.Aggregate(13.0, {}); // lies in third bucket + aggr.Aggregate(252.0, {}); // lies in eight bucket histogram_data = nostd::get(aggr.ToPoint()); EXPECT_EQ(histogram_data.count_, 4); EXPECT_EQ(histogram_data.counts_[3], 2); diff --git a/sdk/test/metrics/async_metric_storage_test.cc b/sdk/test/metrics/async_metric_storage_test.cc index b70d1bf52d..0ce91dafe1 100644 --- a/sdk/test/metrics/async_metric_storage_test.cc +++ b/sdk/test/metrics/async_metric_storage_test.cc @@ -1,8 +1,8 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -#include "opentelemetry/sdk/metrics/state/async_metric_storage.h" -#include +#include "common.h" + #include "opentelemetry/common/key_value_iterable_view.h" #include "opentelemetry/sdk/metrics/async_instruments.h" #include "opentelemetry/sdk/metrics/instruments.h" @@ -10,38 +10,22 @@ #include "opentelemetry/sdk/metrics/metric_reader.h" #include "opentelemetry/sdk/metrics/observer_result.h" #include "opentelemetry/sdk/metrics/push_metric_exporter.h" +#include "opentelemetry/sdk/metrics/state/async_metric_storage.h" #include "opentelemetry/sdk/metrics/state/metric_collector.h" #include "opentelemetry/sdk/metrics/state/observable_registry.h" #include +#include #include #include using namespace opentelemetry::sdk::metrics; using namespace opentelemetry::sdk::instrumentationscope; using namespace opentelemetry::sdk::resource; - -using namespace opentelemetry::sdk::metrics; using namespace opentelemetry::common; -using M = std::map; namespace nostd = opentelemetry::nostd; -class MockCollectorHandle : public CollectorHandle -{ -public: - MockCollectorHandle(AggregationTemporality temp) : temporality(temp) {} - - ~MockCollectorHandle() override = default; - - AggregationTemporality GetAggregationTemporality( - InstrumentType /* instrument_type */) noexcept override - { - return temporality; - } - -private: - AggregationTemporality temporality; -}; +using M = std::map; class WritableMetricStorageTestFixture : public ::testing::TestWithParam {}; @@ -65,10 +49,8 @@ TEST_P(WritableMetricStorageTestFixture, TestAggregation) std::vector> collectors; collectors.push_back(collector); - std::unique_ptr default_attributes_processor{ - new DefaultAttributesProcessor{}}; - opentelemetry::sdk::metrics::AsyncMetricStorage storage( - instr_desc, AggregationType::kSum, default_attributes_processor.get(), nullptr); + opentelemetry::sdk::metrics::AsyncMetricStorage storage(instr_desc, AggregationType::kSum, + nullptr); int64_t get_count1 = 20; int64_t put_count1 = 10; std::unordered_map measurements1 = { @@ -157,10 +139,8 @@ TEST_P(WritableMetricStorageTestObservableGaugeFixture, TestAggregation) std::vector> collectors; collectors.push_back(collector); - std::unique_ptr default_attributes_processor{ - new DefaultAttributesProcessor{}}; - opentelemetry::sdk::metrics::AsyncMetricStorage storage( - instr_desc, AggregationType::kLastValue, default_attributes_processor.get(), nullptr); + opentelemetry::sdk::metrics::AsyncMetricStorage storage(instr_desc, AggregationType::kLastValue, + nullptr); int64_t freq_cpu0 = 3; int64_t freq_cpu1 = 5; std::unordered_map measurements1 = { diff --git a/sdk/test/metrics/attributes_hashmap_benchmark.cc b/sdk/test/metrics/attributes_hashmap_benchmark.cc index 71aaa1cd6f..f0286ec09e 100644 --- a/sdk/test/metrics/attributes_hashmap_benchmark.cc +++ b/sdk/test/metrics/attributes_hashmap_benchmark.cc @@ -32,8 +32,10 @@ void BM_AttributseHashMap(benchmark::State &state) return std::unique_ptr(new DropAggregation); }; m.lock(); - hash_map.GetOrSetDefault(attributes[i % 2], create_default_aggregation)->Aggregate((int64_t)1); - benchmark::DoNotOptimize(hash_map.Has(attributes[i % 2])); + auto hash = opentelemetry::sdk::common::GetHashForAttributeMap(attributes[i % 2]); + hash_map.GetOrSetDefault(attributes[i % 2], create_default_aggregation, hash) + ->Aggregate((int64_t)1); + benchmark::DoNotOptimize(hash_map.Has(hash)); m.unlock(); }; while (state.KeepRunning()) diff --git a/sdk/test/metrics/attributes_hashmap_test.cc b/sdk/test/metrics/attributes_hashmap_test.cc index dd74d5c75b..956a76dfe1 100644 --- a/sdk/test/metrics/attributes_hashmap_test.cc +++ b/sdk/test/metrics/attributes_hashmap_test.cc @@ -18,31 +18,34 @@ TEST(AttributesHashMap, BasicTests) 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); + auto hash = opentelemetry::sdk::common::GetHashForAttributeMap(m1); + + EXPECT_EQ(hash_map.Get(hash), nullptr); + EXPECT_EQ(hash_map.Has(hash), false); // Set std::unique_ptr aggregation1( new DropAggregation()); // = std::unique_ptr(new DropAggregation); - hash_map.Set(m1, std::move(aggregation1)); - EXPECT_NO_THROW(hash_map.Get(m1)->Aggregate((int64_t)1)); + hash_map.Set(m1, std::move(aggregation1), hash); + EXPECT_NO_THROW(hash_map.Get(hash)->Aggregate((int64_t)1)); EXPECT_EQ(hash_map.Size(), 1); - EXPECT_EQ(hash_map.Has(m1), true); + EXPECT_EQ(hash_map.Has(hash), true); // Set same key again auto aggregation2 = std::unique_ptr(new DropAggregation()); - hash_map.Set(m1, std::move(aggregation2)); - EXPECT_NO_THROW(hash_map.Get(m1)->Aggregate((int64_t)1)); + hash_map.Set(m1, std::move(aggregation2), hash); + EXPECT_NO_THROW(hash_map.Get(hash)->Aggregate((int64_t)1)); EXPECT_EQ(hash_map.Size(), 1); - EXPECT_EQ(hash_map.Has(m1), true); + EXPECT_EQ(hash_map.Has(hash), true); // Set more enteria auto aggregation3 = std::unique_ptr(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((int64_t)1)); + auto hash3 = opentelemetry::sdk::common::GetHashForAttributeMap(m3); + hash_map.Set(m3, std::move(aggregation3), hash3); + EXPECT_EQ(hash_map.Has(hash), true); + EXPECT_EQ(hash_map.Has(hash3), true); + EXPECT_NO_THROW(hash_map.Get(hash3)->Aggregate((int64_t)1)); EXPECT_EQ(hash_map.Size(), 2); // GetOrSetDefault @@ -51,12 +54,15 @@ TEST(AttributesHashMap, BasicTests) return std::unique_ptr(new DropAggregation); }; MetricAttributes m4 = {{"k1", "v1"}, {"k2", "v2"}, {"k3", "v3"}}; - EXPECT_NO_THROW(hash_map.GetOrSetDefault(m4, create_default_aggregation)->Aggregate((int64_t)1)); + auto hash4 = opentelemetry::sdk::common::GetHashForAttributeMap(m4); + EXPECT_NO_THROW( + hash_map.GetOrSetDefault(m4, create_default_aggregation, hash4)->Aggregate((int64_t)1)); 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); + auto hash5 = opentelemetry::sdk::common::GetHashForAttributeMap(m5); + EXPECT_EQ(hash_map.Has(hash5), true); // GetAllEnteries size_t count = 0; diff --git a/sdk/test/metrics/common.cc b/sdk/test/metrics/common.cc new file mode 100644 index 0000000000..87343f6186 --- /dev/null +++ b/sdk/test/metrics/common.cc @@ -0,0 +1,68 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "common.h" + +using namespace opentelemetry; +using namespace opentelemetry::sdk::instrumentationscope; +using namespace opentelemetry::sdk::metrics; +using namespace opentelemetry::sdk::common; + +// MockMetricExporter + +ExportResult MockMetricExporter::Export(const ResourceMetrics & /*resource_metrics*/) noexcept +{ + return ExportResult::kSuccess; +} + +AggregationTemporality MockMetricExporter::GetAggregationTemporality( + InstrumentType /*instrument_type*/) const noexcept +{ + return AggregationTemporality::kCumulative; +} + +bool MockMetricExporter::ForceFlush(std::chrono::microseconds /* timeout */) noexcept +{ + return true; +} + +bool MockMetricExporter::Shutdown(std::chrono::microseconds /* timeout */) noexcept +{ + return true; +} + +// MockMetricReader +MockMetricReader::MockMetricReader(std::unique_ptr exporter) + : exporter_(std::move(exporter)) +{} + +MockMetricReader::MockMetricReader() : exporter_{new MockMetricExporter()} {} + +AggregationTemporality MockMetricReader::GetAggregationTemporality( + InstrumentType instrument_type) const noexcept + +{ + return exporter_->GetAggregationTemporality(instrument_type); +} + +bool MockMetricReader::OnForceFlush(std::chrono::microseconds /* timeout */) noexcept +{ + return true; +} + +bool MockMetricReader::OnShutDown(std::chrono::microseconds /* timeout */) noexcept +{ + return true; +} + +void MockMetricReader::OnInitialized() noexcept {} + +// MockCollectorHandle + +MockCollectorHandle::MockCollectorHandle(AggregationTemporality temp) : temporality_(temp) {} + +AggregationTemporality MockCollectorHandle::GetAggregationTemporality( + InstrumentType /* instrument_type */) noexcept +{ + return temporality_; +} diff --git a/sdk/test/metrics/common.h b/sdk/test/metrics/common.h new file mode 100644 index 0000000000..b3b73e15d6 --- /dev/null +++ b/sdk/test/metrics/common.h @@ -0,0 +1,60 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "opentelemetry/sdk/metrics/data/point_data.h" +#include "opentelemetry/sdk/metrics/metric_reader.h" +#include "opentelemetry/sdk/metrics/push_metric_exporter.h" +#include "opentelemetry/sdk/metrics/state/metric_collector.h" + +#include + +class MockMetricExporter : public opentelemetry::sdk::metrics::PushMetricExporter +{ +public: + MockMetricExporter() = default; + opentelemetry::sdk::common::ExportResult Export( + const opentelemetry::sdk::metrics::ResourceMetrics &) noexcept override; + + opentelemetry::sdk::metrics::AggregationTemporality GetAggregationTemporality( + opentelemetry::sdk::metrics::InstrumentType) const noexcept override; + + bool ForceFlush(std::chrono::microseconds) noexcept override; + + bool Shutdown(std::chrono::microseconds) noexcept override; +}; + +class MockMetricReader : public opentelemetry::sdk::metrics::MetricReader +{ +public: + MockMetricReader(std::unique_ptr); + + MockMetricReader(); + + opentelemetry::sdk::metrics::AggregationTemporality GetAggregationTemporality( + opentelemetry::sdk::metrics::InstrumentType) const noexcept override; + + bool OnForceFlush(std::chrono::microseconds) noexcept override; + + bool OnShutDown(std::chrono::microseconds) noexcept override; + + void OnInitialized() noexcept override; + +private: + std::unique_ptr exporter_; +}; + +class MockCollectorHandle : public opentelemetry::sdk::metrics::CollectorHandle +{ +public: + MockCollectorHandle(opentelemetry::sdk::metrics::AggregationTemporality); + + ~MockCollectorHandle() override = default; + + opentelemetry::sdk::metrics::AggregationTemporality GetAggregationTemporality( + opentelemetry::sdk::metrics::InstrumentType) noexcept override; + +private: + opentelemetry::sdk::metrics::AggregationTemporality temporality_; +}; diff --git a/sdk/test/metrics/exemplar/BUILD b/sdk/test/metrics/exemplar/BUILD index 1009999d02..61281af745 100644 --- a/sdk/test/metrics/exemplar/BUILD +++ b/sdk/test/metrics/exemplar/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + cc_test( name = "no_exemplar_reservoir_test", srcs = [ diff --git a/sdk/test/metrics/exemplar/CMakeLists.txt b/sdk/test/metrics/exemplar/CMakeLists.txt index 33d04e913c..b4d5cfe793 100644 --- a/sdk/test/metrics/exemplar/CMakeLists.txt +++ b/sdk/test/metrics/exemplar/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + foreach( testname no_exemplar_reservoir_test never_sample_filter_test always_sample_filter_test diff --git a/sdk/test/metrics/histogram_aggregation_benchmark.cc b/sdk/test/metrics/histogram_aggregation_benchmark.cc new file mode 100644 index 0000000000..bb63f1230c --- /dev/null +++ b/sdk/test/metrics/histogram_aggregation_benchmark.cc @@ -0,0 +1,78 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "common.h" + +#include "opentelemetry/sdk/metrics/data/point_data.h" +#include "opentelemetry/sdk/metrics/meter.h" +#include "opentelemetry/sdk/metrics/meter_context.h" +#include "opentelemetry/sdk/metrics/meter_provider.h" +#include "opentelemetry/sdk/metrics/metric_reader.h" +#include "opentelemetry/sdk/metrics/push_metric_exporter.h" + +#include +#include + +using namespace opentelemetry; +using namespace opentelemetry::sdk::instrumentationscope; +using namespace opentelemetry::sdk::metrics; + +namespace +{ +void BM_HistogramAggregation(benchmark::State &state) +{ + MeterProvider mp; + auto m = mp.GetMeter("meter1", "version1", "schema1"); + + std::unique_ptr exporter(new MockMetricExporter()); + std::shared_ptr reader{new MockMetricReader(std::move(exporter))}; + mp.AddMetricReader(reader); + auto h = m->CreateDoubleHistogram("histogram1", "histogram1_description", "histogram1_unit"); + std::default_random_engine generator; + std::uniform_int_distribution distribution(0, 1000000); + // Generate 100000 measurements + constexpr size_t TOTAL_MEASUREMENTS = 100000; + double measurements[TOTAL_MEASUREMENTS]; + for (size_t i = 0; i < TOTAL_MEASUREMENTS; i++) + { + measurements[i] = (double)distribution(generator); + } + std::vector actuals; + std::vector collectionThreads; + std::function collectMetrics = [&reader, &actuals]() { + reader->Collect([&](ResourceMetrics &rm) { + for (const ScopeMetrics &smd : rm.scope_metric_data_) + { + for (const MetricData &md : smd.metric_data_) + { + for (const PointDataAttributes &dp : md.point_data_attr_) + { + actuals.push_back(opentelemetry::nostd::get(dp.point_data)); + } + } + } + return true; + }); + }; + + while (state.KeepRunning()) + { + for (size_t i = 0; i < TOTAL_MEASUREMENTS; i++) + { + h->Record(measurements[i], {}); + if (i % 1000 == 0 || i == TOTAL_MEASUREMENTS - 1) + { + collectMetrics(); + } + if (i == 100) + { + std::this_thread::sleep_for(std::chrono::nanoseconds(4)); + } + } + } +} + +BENCHMARK(BM_HistogramAggregation); + +} // namespace +BENCHMARK_MAIN(); diff --git a/sdk/test/metrics/histogram_aggregation_test.cc b/sdk/test/metrics/histogram_aggregation_test.cc new file mode 100644 index 0000000000..fada036747 --- /dev/null +++ b/sdk/test/metrics/histogram_aggregation_test.cc @@ -0,0 +1,115 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "common.h" + +#include "opentelemetry/common/macros.h" +#include "opentelemetry/sdk/metrics/data/point_data.h" +#include "opentelemetry/sdk/metrics/meter.h" +#include "opentelemetry/sdk/metrics/meter_context.h" +#include "opentelemetry/sdk/metrics/meter_provider.h" +#include "opentelemetry/sdk/metrics/metric_reader.h" +#include "opentelemetry/sdk/metrics/push_metric_exporter.h" + +#include + +#if OPENTELEMETRY_HAVE_WORKING_REGEX + +using namespace opentelemetry; +using namespace opentelemetry::sdk::instrumentationscope; +using namespace opentelemetry::sdk::metrics; + +TEST(HistogramInstrumentToHistogramAggregation, Double) +{ + MeterProvider mp; + auto m = mp.GetMeter("meter1", "version1", "schema1"); + + std::unique_ptr exporter(new MockMetricExporter()); + std::shared_ptr reader{new MockMetricReader(std::move(exporter))}; + mp.AddMetricReader(reader); + + auto h = m->CreateDoubleHistogram("histogram1", "histogram1_description", "histogram1_unit"); + + h->Record(5, {}); + h->Record(10, {}); + h->Record(15, {}); + h->Record(20, {}); + h->Record(25, {}); + h->Record(30, {}); + h->Record(35, {}); + h->Record(40, {}); + h->Record(45, {}); + h->Record(50, {}); + h->Record(1e6, {}); + + std::vector actuals; + reader->Collect([&](ResourceMetrics &rm) { + for (const ScopeMetrics &smd : rm.scope_metric_data_) + { + for (const MetricData &md : smd.metric_data_) + { + for (const PointDataAttributes &dp : md.point_data_attr_) + { + actuals.push_back(opentelemetry::nostd::get(dp.point_data)); + } + } + } + return true; + }); + + ASSERT_EQ(1, actuals.size()); + const auto &actual = actuals.at(0); + ASSERT_EQ(1000275.0, opentelemetry::nostd::get(actual.sum_)); + ASSERT_EQ(11, actual.count_); +} + +TEST(CounterToHistogram, Double) +{ + MeterProvider mp; + auto m = mp.GetMeter("meter1", "version1", "schema1"); + + std::unique_ptr exporter(new MockMetricExporter()); + std::shared_ptr reader{new MockMetricReader(std::move(exporter))}; + mp.AddMetricReader(reader); + + std::unique_ptr view{new View("view1", "view1_description", AggregationType::kHistogram)}; + std::unique_ptr instrument_selector{ + new InstrumentSelector(InstrumentType::kCounter, "counter1")}; + std::unique_ptr meter_selector{new MeterSelector("meter1", "version1", "schema1")}; + mp.AddView(std::move(instrument_selector), std::move(meter_selector), std::move(view)); + + auto h = m->CreateDoubleCounter("counter1", "counter1_description", "counter1_unit"); + + h->Add(5, {}); + h->Add(10, {}); + h->Add(15, {}); + h->Add(20, {}); + h->Add(25, {}); + h->Add(30, {}); + h->Add(35, {}); + h->Add(40, {}); + h->Add(45, {}); + h->Add(50, {}); + h->Add(1e6, {}); + + std::vector actuals; + reader->Collect([&](ResourceMetrics &rm) { + for (const ScopeMetrics &smd : rm.scope_metric_data_) + { + for (const MetricData &md : smd.metric_data_) + { + for (const PointDataAttributes &dp : md.point_data_attr_) + { + actuals.push_back(opentelemetry::nostd::get(dp.point_data)); + } + } + } + return true; + }); + + ASSERT_EQ(1, actuals.size()); + const auto &actual = actuals.at(0); + ASSERT_EQ(1000275.0, opentelemetry::nostd::get(actual.sum_)); + ASSERT_EQ(11, actual.count_); +} +#endif diff --git a/sdk/test/metrics/histogram_test.cc b/sdk/test/metrics/histogram_test.cc new file mode 100644 index 0000000000..ef2d023c92 --- /dev/null +++ b/sdk/test/metrics/histogram_test.cc @@ -0,0 +1,246 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "common.h" + +#include "opentelemetry/common/macros.h" +#include "opentelemetry/sdk/metrics/data/point_data.h" +#include "opentelemetry/sdk/metrics/meter.h" +#include "opentelemetry/sdk/metrics/meter_context.h" +#include "opentelemetry/sdk/metrics/meter_provider.h" +#include "opentelemetry/sdk/metrics/metric_reader.h" +#include "opentelemetry/sdk/metrics/push_metric_exporter.h" + +#include + +#if defined(OPENTELEMETRY_HAVE_WORKING_REGEX) +# include +#endif + +using namespace opentelemetry; +using namespace opentelemetry::sdk::instrumentationscope; +using namespace opentelemetry::sdk::metrics; + +TEST(Histogram, Double) +{ + MeterProvider mp; + auto m = mp.GetMeter("meter1", "version1", "schema1"); + + std::unique_ptr exporter(new MockMetricExporter()); + std::shared_ptr reader{new MockMetricReader(std::move(exporter))}; + mp.AddMetricReader(reader); + + auto h = m->CreateDoubleHistogram("histogram1", "histogram1_description", "histogram1_unit"); + + h->Record(5, {}); + h->Record(10, {}); + h->Record(15, {}); + h->Record(20, {}); + h->Record(25, {}); + h->Record(30, {}); + h->Record(35, {}); + h->Record(40, {}); + h->Record(45, {}); + h->Record(50, {}); + h->Record(1e6, {}); + + std::vector actuals; + reader->Collect([&](ResourceMetrics &rm) { + for (const ScopeMetrics &smd : rm.scope_metric_data_) + { + for (const MetricData &md : smd.metric_data_) + { + for (const PointDataAttributes &dp : md.point_data_attr_) + { + actuals.push_back(opentelemetry::nostd::get(dp.point_data)); + } + } + } + return true; + }); + + ASSERT_EQ(1, actuals.size()); + + const auto &actual = actuals.at(0); + ASSERT_EQ(1000275.0, opentelemetry::nostd::get(actual.sum_)); + ASSERT_EQ(11, actual.count_); + ASSERT_EQ(5.0, opentelemetry::nostd::get(actual.min_)); + ASSERT_EQ(1e6, opentelemetry::nostd::get(actual.max_)); + ASSERT_EQ(std::vector( + {0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000}), + actual.boundaries_); + ASSERT_EQ(std::vector({0, 1, 1, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}), + actual.counts_); +} + +#if (OPENTELEMETRY_HAVE_WORKING_REGEX) +// FIXME - View Preficate search is only supported through regex +TEST(Histogram, DoubleCustomBuckets) +{ + MeterProvider mp; + auto m = mp.GetMeter("meter1", "version1", "schema1"); + + std::unique_ptr exporter(new MockMetricExporter()); + std::shared_ptr reader{new MockMetricReader(std::move(exporter))}; + mp.AddMetricReader(reader); + + std::shared_ptr config(new HistogramAggregationConfig()); + config->boundaries_ = {10, 20, 30, 40}; + std::unique_ptr view{ + new View("view1", "view1_description", AggregationType::kHistogram, config)}; + std::unique_ptr instrument_selector{ + new InstrumentSelector(InstrumentType::kHistogram, "histogram1")}; + std::unique_ptr meter_selector{new MeterSelector("meter1", "version1", "schema1")}; + mp.AddView(std::move(instrument_selector), std::move(meter_selector), std::move(view)); + + auto h = m->CreateDoubleHistogram("histogram1", "histogram1_description", "histogram1_unit"); + + h->Record(5, {}); + h->Record(10, {}); + h->Record(15, {}); + h->Record(20, {}); + h->Record(25, {}); + h->Record(30, {}); + h->Record(35, {}); + h->Record(40, {}); + h->Record(45, {}); + h->Record(50, {}); + + std::vector actuals; + reader->Collect([&](ResourceMetrics &rm) { + for (const ScopeMetrics &smd : rm.scope_metric_data_) + { + for (const MetricData &md : smd.metric_data_) + { + for (const PointDataAttributes &dp : md.point_data_attr_) + { + actuals.push_back(opentelemetry::nostd::get(dp.point_data)); + } + } + } + return true; + }); + + ASSERT_EQ(1, actuals.size()); + + const auto &actual = actuals.at(0); + ASSERT_EQ(275.0, opentelemetry::nostd::get(actual.sum_)); + ASSERT_EQ(10, actual.count_); + ASSERT_EQ(5.0, opentelemetry::nostd::get(actual.min_)); + ASSERT_EQ(50.0, opentelemetry::nostd::get(actual.max_)); + ASSERT_EQ(std::vector({10, 20, 30, 40}), actual.boundaries_); + ASSERT_EQ(std::vector({2, 2, 2, 2, 2}), actual.counts_); +} +#endif + +TEST(Histogram, UInt64) +{ + MeterProvider mp; + auto m = mp.GetMeter("meter1", "version1", "schema1"); + + std::unique_ptr exporter(new MockMetricExporter()); + std::shared_ptr reader{new MockMetricReader(std::move(exporter))}; + mp.AddMetricReader(reader); + + auto h = m->CreateUInt64Histogram("histogram1", "histogram1_description", "histogram1_unit"); + + h->Record(5, {}); + h->Record(10, {}); + h->Record(15, {}); + h->Record(20, {}); + h->Record(25, {}); + h->Record(30, {}); + h->Record(35, {}); + h->Record(40, {}); + h->Record(45, {}); + h->Record(50, {}); + h->Record(1000000, {}); + + std::vector actuals; + reader->Collect([&](ResourceMetrics &rm) { + for (const ScopeMetrics &smd : rm.scope_metric_data_) + { + for (const MetricData &md : smd.metric_data_) + { + for (const PointDataAttributes &dp : md.point_data_attr_) + { + actuals.push_back(opentelemetry::nostd::get(dp.point_data)); + } + } + } + return true; + }); + + ASSERT_EQ(1, actuals.size()); + + const auto &actual = actuals.at(0); + ASSERT_EQ(1000275, opentelemetry::nostd::get(actual.sum_)); + ASSERT_EQ(11, actual.count_); + ASSERT_EQ(5, opentelemetry::nostd::get(actual.min_)); + ASSERT_EQ(1000000, opentelemetry::nostd::get(actual.max_)); + ASSERT_EQ(std::vector( + {0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000}), + actual.boundaries_); + ASSERT_EQ(std::vector({0, 1, 1, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}), + actual.counts_); +} + +#if (OPENTELEMETRY_HAVE_WORKING_REGEX) +// FIXME - View Preficate search is only supported through regex +TEST(Histogram, UInt64CustomBuckets) +{ + MeterProvider mp; + auto m = mp.GetMeter("meter1", "version1", "schema1"); + + std::unique_ptr exporter(new MockMetricExporter()); + std::shared_ptr reader{new MockMetricReader(std::move(exporter))}; + mp.AddMetricReader(reader); + + std::shared_ptr config(new HistogramAggregationConfig()); + config->boundaries_ = {10, 20, 30, 40}; + std::unique_ptr view{ + new View("view1", "view1_description", AggregationType::kHistogram, config)}; + std::unique_ptr instrument_selector{ + new InstrumentSelector(InstrumentType::kHistogram, "histogram1")}; + std::unique_ptr meter_selector{new MeterSelector("meter1", "version1", "schema1")}; + mp.AddView(std::move(instrument_selector), std::move(meter_selector), std::move(view)); + + auto h = m->CreateUInt64Histogram("histogram1", "histogram1_description", "histogram1_unit"); + + h->Record(5, {}); + h->Record(10, {}); + h->Record(15, {}); + h->Record(20, {}); + h->Record(25, {}); + h->Record(30, {}); + h->Record(35, {}); + h->Record(40, {}); + h->Record(45, {}); + h->Record(50, {}); + + std::vector actuals; + reader->Collect([&](ResourceMetrics &rm) { + for (const ScopeMetrics &smd : rm.scope_metric_data_) + { + for (const MetricData &md : smd.metric_data_) + { + for (const PointDataAttributes &dp : md.point_data_attr_) + { + actuals.push_back(opentelemetry::nostd::get(dp.point_data)); + } + } + } + return true; + }); + + ASSERT_EQ(1, actuals.size()); + + const auto &actual = actuals.at(0); + ASSERT_EQ(275, opentelemetry::nostd::get(actual.sum_)); + ASSERT_EQ(10, actual.count_); + ASSERT_EQ(5, opentelemetry::nostd::get(actual.min_)); + ASSERT_EQ(50, opentelemetry::nostd::get(actual.max_)); + ASSERT_EQ(std::vector({10, 20, 30, 40}), actual.boundaries_); + ASSERT_EQ(std::vector({2, 2, 2, 2, 2}), actual.counts_); +} +#endif diff --git a/sdk/test/metrics/measurements_benchmark.cc b/sdk/test/metrics/measurements_benchmark.cc new file mode 100644 index 0000000000..06ac75a65a --- /dev/null +++ b/sdk/test/metrics/measurements_benchmark.cc @@ -0,0 +1,86 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/sdk/metrics/meter.h" +#include "opentelemetry/sdk/metrics/meter_context.h" +#include "opentelemetry/sdk/metrics/meter_provider.h" +#include "opentelemetry/sdk/metrics/metric_reader.h" +#include "opentelemetry/sdk/metrics/push_metric_exporter.h" + +#include +#include +#include + +using namespace opentelemetry; +using namespace opentelemetry::sdk::instrumentationscope; +using namespace opentelemetry::sdk::metrics; +using namespace opentelemetry::sdk::common; + +class MockMetricExporter : public MetricReader +{ +public: + MockMetricExporter() = default; + + opentelemetry::sdk::metrics::AggregationTemporality GetAggregationTemporality( + opentelemetry::sdk::metrics::InstrumentType) const noexcept override + { + return AggregationTemporality::kCumulative; + } + +private: + bool OnForceFlush(std::chrono::microseconds /*timeout*/) noexcept override { return true; } + + bool OnShutDown(std::chrono::microseconds /*timeout*/) noexcept override { return true; } + + void OnInitialized() noexcept override {} +}; + +namespace +{ +void BM_MeasurementsTest(benchmark::State &state) +{ + MeterProvider mp; + auto m = mp.GetMeter("meter1", "version1", "schema1"); + + std::shared_ptr exporter(new MockMetricExporter()); + mp.AddMetricReader(exporter); + auto h = m->CreateDoubleCounter("counter1", "counter1_description", "counter1_unit"); + size_t MAX_MEASUREMENTS = 10000; // keep low to prevent CI failure due to timeout + size_t NUM_CORES = 1; + std::vector threads; + std::map attributes[1000]; + size_t total_index = 0; + for (uint32_t i = 0; i < 10; i++) + { + for (uint32_t j = 0; j < 10; j++) + for (uint32_t k = 0; k < 10; k++) + attributes[total_index++] = {{"dim1", i}, {"dim2", j}, {"dim3", k}}; + } + while (state.KeepRunning()) + { + threads.clear(); + std::atomic cur_processed{0}; + for (size_t i = 0; i < NUM_CORES; i++) + { + threads.push_back(std::thread([&h, &cur_processed, &MAX_MEASUREMENTS, &attributes]() { + while (cur_processed++ <= MAX_MEASUREMENTS) + { + size_t index = rand() % 1000; + h->Add(1.0, + opentelemetry::common::KeyValueIterableView>( + attributes[index]), + opentelemetry::context::Context{}); + } + })); + } + for (auto &thread : threads) + { + thread.join(); + } + } + exporter->Collect([&](ResourceMetrics & /*rm*/) { return true; }); +} +BENCHMARK(BM_MeasurementsTest); + +} // namespace +BENCHMARK_MAIN(); diff --git a/sdk/test/metrics/meter_provider_sdk_test.cc b/sdk/test/metrics/meter_provider_sdk_test.cc index 7663ca9b01..bcdc6c4b79 100644 --- a/sdk/test/metrics/meter_provider_sdk_test.cc +++ b/sdk/test/metrics/meter_provider_sdk_test.cc @@ -1,6 +1,8 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +#include "common.h" + #include #include "opentelemetry/sdk/metrics/export/metric_producer.h" #include "opentelemetry/sdk/metrics/meter.h" @@ -12,51 +14,6 @@ using namespace opentelemetry::sdk::metrics; -class MockMetricExporter : public PushMetricExporter -{ - -public: - MockMetricExporter() = default; - opentelemetry::sdk::common::ExportResult Export( - const ResourceMetrics & /* records */) noexcept override - { - return opentelemetry::sdk::common::ExportResult::kSuccess; - } - - AggregationTemporality GetAggregationTemporality( - InstrumentType /* instrument_type */) const noexcept override - { - return AggregationTemporality::kCumulative; - } - - bool ForceFlush(std::chrono::microseconds /* timeout */) noexcept override { return true; } - - bool Shutdown(std::chrono::microseconds /* timeout */) noexcept override { return true; } -}; - -class MockMetricReader : public MetricReader -{ -public: - MockMetricReader(std::unique_ptr exporter) : exporter_(std::move(exporter)) {} - AggregationTemporality GetAggregationTemporality( - InstrumentType instrument_type) const noexcept override - { - return exporter_->GetAggregationTemporality(instrument_type); - } - 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 exporter_; -}; - TEST(MeterProvider, GetMeter) { diff --git a/sdk/test/metrics/meter_test.cc b/sdk/test/metrics/meter_test.cc index fb260ea19d..084f50fc09 100644 --- a/sdk/test/metrics/meter_test.cc +++ b/sdk/test/metrics/meter_test.cc @@ -1,8 +1,10 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -#include "opentelemetry/sdk/metrics/meter.h" +#include "common.h" + #include "opentelemetry/sdk/metrics/data/point_data.h" +#include "opentelemetry/sdk/metrics/meter.h" #include "opentelemetry/sdk/metrics/meter_context.h" #include "opentelemetry/sdk/metrics/meter_provider.h" #include "opentelemetry/sdk/metrics/metric_reader.h" @@ -13,20 +15,6 @@ using namespace opentelemetry; using namespace opentelemetry::sdk::instrumentationscope; using namespace opentelemetry::sdk::metrics; -class MockMetricReader : public MetricReader -{ -public: - MockMetricReader() = default; - AggregationTemporality GetAggregationTemporality( - InstrumentType /* instrument_type */) const noexcept override - { - return AggregationTemporality::kCumulative; - } - bool OnShutDown(std::chrono::microseconds /* timeout */) noexcept override { return true; } - bool OnForceFlush(std::chrono::microseconds /* timeout */) noexcept override { return true; } - void OnInitialized() noexcept override {} -}; - namespace { nostd::shared_ptr InitMeter(MetricReader **metricReaderPtr, diff --git a/sdk/test/metrics/metric_reader_test.cc b/sdk/test/metrics/metric_reader_test.cc index de787d617c..061d505a1d 100644 --- a/sdk/test/metrics/metric_reader_test.cc +++ b/sdk/test/metrics/metric_reader_test.cc @@ -1,35 +1,17 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -#include "opentelemetry/sdk/metrics/metric_reader.h" +#include "common.h" + #include #include "opentelemetry/sdk/metrics/meter_context.h" +#include "opentelemetry/sdk/metrics/metric_reader.h" #include "opentelemetry/sdk/metrics/push_metric_exporter.h" using namespace opentelemetry; using namespace opentelemetry::sdk::instrumentationscope; using namespace opentelemetry::sdk::metrics; -class MockMetricReader : public MetricReader -{ -public: - MockMetricReader() = default; - AggregationTemporality GetAggregationTemporality( - InstrumentType /* instrument_type */) const noexcept override - { - return AggregationTemporality::kCumulative; - } - 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) { std::unique_ptr metric_reader1(new MockMetricReader()); diff --git a/sdk/test/metrics/periodic_exporting_metric_reader_test.cc b/sdk/test/metrics/periodic_exporting_metric_reader_test.cc index cd789b5028..e115f79f75 100644 --- a/sdk/test/metrics/periodic_exporting_metric_reader_test.cc +++ b/sdk/test/metrics/periodic_exporting_metric_reader_test.cc @@ -70,6 +70,7 @@ TEST(PeriodicExporingMetricReader, BasicTests) MockMetricProducer producer; reader.SetMetricProducer(&producer); std::this_thread::sleep_for(std::chrono::milliseconds(2000)); + EXPECT_NO_THROW(reader.ForceFlush()); reader.Shutdown(); EXPECT_EQ(static_cast(exporter_ptr)->GetDataCount(), static_cast(&producer)->GetDataCount()); diff --git a/sdk/test/metrics/sum_aggregation_benchmark.cc b/sdk/test/metrics/sum_aggregation_benchmark.cc new file mode 100644 index 0000000000..43be12523a --- /dev/null +++ b/sdk/test/metrics/sum_aggregation_benchmark.cc @@ -0,0 +1,79 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "common.h" + +#include "opentelemetry/sdk/metrics/data/point_data.h" +#include "opentelemetry/sdk/metrics/meter.h" +#include "opentelemetry/sdk/metrics/meter_context.h" +#include "opentelemetry/sdk/metrics/meter_provider.h" +#include "opentelemetry/sdk/metrics/metric_reader.h" +#include "opentelemetry/sdk/metrics/push_metric_exporter.h" + +#include +#include +#include + +using namespace opentelemetry; +using namespace opentelemetry::sdk::instrumentationscope; +using namespace opentelemetry::sdk::metrics; + +namespace +{ +void BM_SumAggregation(benchmark::State &state) +{ + MeterProvider mp; + auto m = mp.GetMeter("meter1", "version1", "schema1"); + + std::unique_ptr exporter(new MockMetricExporter()); + std::shared_ptr reader{new MockMetricReader(std::move(exporter))}; + mp.AddMetricReader(reader); + auto h = m->CreateDoubleCounter("counter1", "counter1_description", "counter1_unit"); + std::default_random_engine generator; + std::uniform_int_distribution distribution(0, 1000000); + // Generate 100000 measurements + constexpr size_t TOTAL_MEASUREMENTS = 100000; + double measurements[TOTAL_MEASUREMENTS]; + for (size_t i = 0; i < TOTAL_MEASUREMENTS; i++) + { + measurements[i] = (double)distribution(generator); + } + std::vector actuals; + std::vector collectionThreads; + std::function collectMetrics = [&reader, &actuals]() { + reader->Collect([&](ResourceMetrics &rm) { + for (const ScopeMetrics &smd : rm.scope_metric_data_) + { + for (const MetricData &md : smd.metric_data_) + { + for (const PointDataAttributes &dp : md.point_data_attr_) + { + actuals.push_back(opentelemetry::nostd::get(dp.point_data)); + } + } + } + return true; + }); + }; + + while (state.KeepRunning()) + { + for (size_t i = 0; i < TOTAL_MEASUREMENTS; i++) + { + h->Add(measurements[i], {}); + if (i % 1000 == 0 || i == TOTAL_MEASUREMENTS - 1) + { + collectMetrics(); + } + if (i == 500) + { + std::this_thread::sleep_for(std::chrono::nanoseconds(2)); + } + } + } +} + +BENCHMARK(BM_SumAggregation); + +} // namespace +BENCHMARK_MAIN(); diff --git a/sdk/test/metrics/sum_aggregation_test.cc b/sdk/test/metrics/sum_aggregation_test.cc new file mode 100644 index 0000000000..9fb1804022 --- /dev/null +++ b/sdk/test/metrics/sum_aggregation_test.cc @@ -0,0 +1,163 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "common.h" + +#include "opentelemetry/common/macros.h" +#include "opentelemetry/sdk/metrics/data/point_data.h" +#include "opentelemetry/sdk/metrics/meter.h" +#include "opentelemetry/sdk/metrics/meter_context.h" +#include "opentelemetry/sdk/metrics/meter_provider.h" +#include "opentelemetry/sdk/metrics/metric_reader.h" +#include "opentelemetry/sdk/metrics/push_metric_exporter.h" + +#include + +#if OPENTELEMETRY_HAVE_WORKING_REGEX + +using namespace opentelemetry; +using namespace opentelemetry::sdk::instrumentationscope; +using namespace opentelemetry::sdk::metrics; + +TEST(HistogramToSum, Double) +{ + MeterProvider mp; + auto m = mp.GetMeter("meter1", "version1", "schema1"); + + std::unique_ptr exporter(new MockMetricExporter()); + std::shared_ptr reader{new MockMetricReader(std::move(exporter))}; + mp.AddMetricReader(reader); + + std::unique_ptr view{new View("view1", "view1_description", AggregationType::kSum)}; + std::unique_ptr instrument_selector{ + new InstrumentSelector(InstrumentType::kHistogram, "histogram1")}; + std::unique_ptr meter_selector{new MeterSelector("meter1", "version1", "schema1")}; + mp.AddView(std::move(instrument_selector), std::move(meter_selector), std::move(view)); + + auto h = m->CreateDoubleHistogram("histogram1", "histogram1_description", "histogram1_unit"); + + h->Record(5, {}); + h->Record(10, {}); + h->Record(15, {}); + h->Record(20, {}); + h->Record(25, {}); + h->Record(30, {}); + h->Record(35, {}); + h->Record(40, {}); + h->Record(45, {}); + h->Record(50, {}); + h->Record(1e6, {}); + + std::vector actuals; + reader->Collect([&](ResourceMetrics &rm) { + for (const ScopeMetrics &smd : rm.scope_metric_data_) + { + for (const MetricData &md : smd.metric_data_) + { + for (const PointDataAttributes &dp : md.point_data_attr_) + { + actuals.push_back(opentelemetry::nostd::get(dp.point_data)); + } + } + } + return true; + }); + + ASSERT_EQ(1, actuals.size()); + const auto &actual = actuals.at(0); + ASSERT_EQ(1000275.0, opentelemetry::nostd::get(actual.value_)); +} + +TEST(CounterToSum, Double) +{ + MeterProvider mp; + auto m = mp.GetMeter("meter1", "version1", "schema1"); + + std::unique_ptr exporter(new MockMetricExporter()); + std::shared_ptr reader{new MockMetricReader(std::move(exporter))}; + mp.AddMetricReader(reader); + + std::unique_ptr view{new View("view1", "view1_description", AggregationType::kSum)}; + std::unique_ptr instrument_selector{ + new InstrumentSelector(InstrumentType::kCounter, "counter1")}; + std::unique_ptr meter_selector{new MeterSelector("meter1", "version1", "schema1")}; + mp.AddView(std::move(instrument_selector), std::move(meter_selector), std::move(view)); + + auto h = m->CreateDoubleCounter("counter1", "counter1_description", "counter1_unit"); + + h->Add(5, {}); + h->Add(10, {}); + h->Add(15, {}); + h->Add(20, {}); + h->Add(25, {}); + h->Add(30, {}); + h->Add(35, {}); + h->Add(40, {}); + h->Add(45, {}); + h->Add(50, {}); + h->Add(1e6, {}); + + std::vector actuals; + reader->Collect([&](ResourceMetrics &rm) { + for (const ScopeMetrics &smd : rm.scope_metric_data_) + { + for (const MetricData &md : smd.metric_data_) + { + for (const PointDataAttributes &dp : md.point_data_attr_) + { + actuals.push_back(opentelemetry::nostd::get(dp.point_data)); + } + } + } + return true; + }); + + ASSERT_EQ(1, actuals.size()); + const auto &actual = actuals.at(0); + ASSERT_EQ(1000275.0, opentelemetry::nostd::get(actual.value_)); +} + +TEST(UpDownCounterToSum, Double) +{ + MeterProvider mp; + auto m = mp.GetMeter("meter1", "version1", "schema1"); + + std::unique_ptr exporter(new MockMetricExporter()); + std::shared_ptr reader{new MockMetricReader(std::move(exporter))}; + mp.AddMetricReader(reader); + + std::unique_ptr view{new View("view1", "view1_description", AggregationType::kSum)}; + std::unique_ptr instrument_selector{ + new InstrumentSelector(InstrumentType::kUpDownCounter, "counter1")}; + std::unique_ptr meter_selector{new MeterSelector("meter1", "version1", "schema1")}; + mp.AddView(std::move(instrument_selector), std::move(meter_selector), std::move(view)); + + auto h = m->CreateDoubleUpDownCounter("counter1", "counter1_description", "counter1_unit"); + + h->Add(5, {}); + h->Add(10, {}); + h->Add(-15, {}); + h->Add(20, {}); + h->Add(25, {}); + h->Add(-30, {}); + + std::vector actuals; + reader->Collect([&](ResourceMetrics &rm) { + for (const ScopeMetrics &smd : rm.scope_metric_data_) + { + for (const MetricData &md : smd.metric_data_) + { + for (const PointDataAttributes &dp : md.point_data_attr_) + { + actuals.push_back(opentelemetry::nostd::get(dp.point_data)); + } + } + } + return true; + }); + + ASSERT_EQ(1, actuals.size()); + const auto &actual = actuals.at(0); + ASSERT_EQ(15.0, opentelemetry::nostd::get(actual.value_)); +} +#endif diff --git a/sdk/test/metrics/sync_instruments_test.cc b/sdk/test/metrics/sync_instruments_test.cc index 0747115bab..a1ff2325e2 100644 --- a/sdk/test/metrics/sync_instruments_test.cc +++ b/sdk/test/metrics/sync_instruments_test.cc @@ -98,15 +98,15 @@ TEST(SyncInstruments, LongHistogram) InstrumentDescriptor instrument_descriptor = { "long_histogram", "description", "1", InstrumentType::kHistogram, InstrumentValueType::kLong}; std::unique_ptr metric_storage(new SyncMultiMetricStorage()); - LongHistogram counter(instrument_descriptor, std::move(metric_storage)); - counter.Record(10, opentelemetry::context::Context{}); - counter.Record(-10, opentelemetry::context::Context{}); // This is ignored - - counter.Record(10, - opentelemetry::common::KeyValueIterableView({{"abc", "123"}, {"xyz", "456"}}), - opentelemetry::context::Context{}); - counter.Record(10, opentelemetry::common::KeyValueIterableView({}), - opentelemetry::context::Context{}); + LongHistogram histogram(instrument_descriptor, std::move(metric_storage)); + histogram.Record(10, opentelemetry::context::Context{}); + histogram.Record(-10, opentelemetry::context::Context{}); // This is ignored + + histogram.Record(10, + opentelemetry::common::KeyValueIterableView({{"abc", "123"}, {"xyz", "456"}}), + opentelemetry::context::Context{}); + histogram.Record(10, opentelemetry::common::KeyValueIterableView({}), + opentelemetry::context::Context{}); } TEST(SyncInstruments, DoubleHistogram) @@ -115,17 +115,17 @@ TEST(SyncInstruments, DoubleHistogram) InstrumentType::kHistogram, InstrumentValueType::kDouble}; std::unique_ptr metric_storage(new SyncMultiMetricStorage()); - DoubleHistogram counter(instrument_descriptor, std::move(metric_storage)); - counter.Record(10.10, opentelemetry::context::Context{}); - counter.Record(-10.10, opentelemetry::context::Context{}); // This is ignored. - counter.Record(std::numeric_limits::quiet_NaN(), - opentelemetry::context::Context{}); // This is ignored too - counter.Record(std::numeric_limits::infinity(), - opentelemetry::context::Context{}); // This is ignored too - - counter.Record(10.10, - opentelemetry::common::KeyValueIterableView({{"abc", "123"}, {"xyz", "456"}}), - opentelemetry::context::Context{}); - counter.Record(10.10, opentelemetry::common::KeyValueIterableView({}), - opentelemetry::context::Context{}); + DoubleHistogram histogram(instrument_descriptor, std::move(metric_storage)); + histogram.Record(10.10, opentelemetry::context::Context{}); + histogram.Record(-10.10, opentelemetry::context::Context{}); // This is ignored. + histogram.Record(std::numeric_limits::quiet_NaN(), + opentelemetry::context::Context{}); // This is ignored too + histogram.Record(std::numeric_limits::infinity(), + opentelemetry::context::Context{}); // This is ignored too + + histogram.Record(10.10, + opentelemetry::common::KeyValueIterableView({{"abc", "123"}, {"xyz", "456"}}), + opentelemetry::context::Context{}); + histogram.Record(10.10, opentelemetry::common::KeyValueIterableView({}), + opentelemetry::context::Context{}); } diff --git a/sdk/test/metrics/sync_metric_storage_counter_test.cc b/sdk/test/metrics/sync_metric_storage_counter_test.cc index 5603a8db05..e27a9f5a24 100644 --- a/sdk/test/metrics/sync_metric_storage_counter_test.cc +++ b/sdk/test/metrics/sync_metric_storage_counter_test.cc @@ -1,6 +1,8 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +#include "common.h" + #include #include "opentelemetry/common/key_value_iterable_view.h" #include "opentelemetry/nostd/shared_ptr.h" @@ -17,23 +19,6 @@ using namespace opentelemetry::common; using M = std::map; namespace nostd = opentelemetry::nostd; -class MockCollectorHandle : public CollectorHandle -{ -public: - MockCollectorHandle(AggregationTemporality temp) : temporality(temp) {} - - ~MockCollectorHandle() override = default; - - AggregationTemporality GetAggregationTemporality( - InstrumentType /* instrument_type */) noexcept override - { - return temporality; - } - -private: - AggregationTemporality temporality; -}; - class WritableMetricStorageTestFixture : public ::testing::TestWithParam {}; @@ -110,6 +95,10 @@ TEST_P(WritableMetricStorageTestFixture, LongCounterSumAggregation) count_attributes = 0; storage.Collect( collector.get(), collectors, sdk_start_ts, collection_ts, [&](const MetricData &metric_data) { + if (temporality == AggregationTemporality::kCumulative) + { + EXPECT_EQ(metric_data.start_ts, sdk_start_ts); + } for (const auto &data_attr : metric_data.point_data_attr_) { const auto &data = opentelemetry::nostd::get(data_attr.point_data); @@ -249,6 +238,10 @@ TEST_P(WritableMetricStorageTestFixture, DoubleCounterSumAggregation) count_attributes = 0; storage.Collect( collector.get(), collectors, sdk_start_ts, collection_ts, [&](const MetricData &metric_data) { + if (temporality == AggregationTemporality::kCumulative) + { + EXPECT_EQ(metric_data.start_ts, sdk_start_ts); + } for (const auto &data_attr : metric_data.point_data_attr_) { const auto &data = opentelemetry::nostd::get(data_attr.point_data); diff --git a/sdk/test/metrics/sync_metric_storage_histogram_test.cc b/sdk/test/metrics/sync_metric_storage_histogram_test.cc index 6544a21a8c..3da2b0538e 100644 --- a/sdk/test/metrics/sync_metric_storage_histogram_test.cc +++ b/sdk/test/metrics/sync_metric_storage_histogram_test.cc @@ -1,7 +1,8 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -#include +#include "common.h" + #include "opentelemetry/common/key_value_iterable_view.h" #include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/sdk/metrics/exemplar/no_exemplar_reservoir.h" @@ -11,29 +12,13 @@ #include #include +#include using namespace opentelemetry::sdk::metrics; using namespace opentelemetry::common; using M = std::map; namespace nostd = opentelemetry::nostd; -class MockCollectorHandle : public CollectorHandle -{ -public: - MockCollectorHandle(AggregationTemporality temp) : temporality(temp) {} - - ~MockCollectorHandle() override = default; - - AggregationTemporality GetAggregationTemporality( - InstrumentType /* instrument_type */) noexcept override - { - return temporality; - } - -private: - AggregationTemporality temporality; -}; - class WritableMetricStorageHistogramTestFixture : public ::testing::TestWithParam {}; @@ -112,6 +97,10 @@ TEST_P(WritableMetricStorageHistogramTestFixture, LongHistogram) count_attributes = 0; storage.Collect( collector.get(), collectors, sdk_start_ts, collection_ts, [&](const MetricData &metric_data) { + if (temporality == AggregationTemporality::kCumulative) + { + EXPECT_EQ(metric_data.start_ts, sdk_start_ts); + } for (const auto &data_attr : metric_data.point_data_attr_) { const auto &data = opentelemetry::nostd::get(data_attr.point_data); @@ -251,6 +240,10 @@ TEST_P(WritableMetricStorageHistogramTestFixture, DoubleHistogram) count_attributes = 0; storage.Collect( collector.get(), collectors, sdk_start_ts, collection_ts, [&](const MetricData &metric_data) { + if (temporality == AggregationTemporality::kCumulative) + { + EXPECT_EQ(metric_data.start_ts, sdk_start_ts); + } for (const auto &data_attr : metric_data.point_data_attr_) { const auto &data = opentelemetry::nostd::get(data_attr.point_data); diff --git a/sdk/test/metrics/sync_metric_storage_up_down_counter_test.cc b/sdk/test/metrics/sync_metric_storage_up_down_counter_test.cc index f84bde7628..15077b428a 100644 --- a/sdk/test/metrics/sync_metric_storage_up_down_counter_test.cc +++ b/sdk/test/metrics/sync_metric_storage_up_down_counter_test.cc @@ -1,6 +1,8 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +#include "common.h" + #include "opentelemetry/common/key_value_iterable_view.h" #include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/sdk/metrics/exemplar/histogram_exemplar_reservoir.h" @@ -17,23 +19,6 @@ using namespace opentelemetry::common; using M = std::map; namespace nostd = opentelemetry::nostd; -class MockCollectorHandle : public CollectorHandle -{ -public: - MockCollectorHandle(AggregationTemporality temp) : temporality(temp) {} - - ~MockCollectorHandle() override = default; - - AggregationTemporality GetAggregationTemporality( - InstrumentType /* instrument_type */) noexcept override - { - return temporality; - } - -private: - AggregationTemporality temporality; -}; - class WritableMetricStorageTestFixture : public ::testing::TestWithParam {}; @@ -114,6 +99,10 @@ TEST_P(WritableMetricStorageTestFixture, LongUpDownCounterSumAggregation) count_attributes = 0; storage.Collect(collector.get(), collectors, sdk_start_ts, collection_ts, [&](const MetricData data) { + if (temporality == AggregationTemporality::kCumulative) + { + EXPECT_EQ(data.start_ts, sdk_start_ts); + } for (auto data_attr : data.point_data_attr_) { auto sum_data = opentelemetry::nostd::get(data_attr.point_data); @@ -261,6 +250,10 @@ TEST_P(WritableMetricStorageTestFixture, DoubleUpDownCounterSumAggregation) count_attributes = 0; storage.Collect(collector.get(), collectors, sdk_start_ts, collection_ts, [&](const MetricData data) { + if (temporality == AggregationTemporality::kCumulative) + { + EXPECT_EQ(data.start_ts, sdk_start_ts); + } for (auto data_attr : data.point_data_attr_) { auto sum_data = opentelemetry::nostd::get(data_attr.point_data); diff --git a/sdk/test/metrics/view_registry_test.cc b/sdk/test/metrics/view_registry_test.cc index 6c07b639ce..59899dedb0 100644 --- a/sdk/test/metrics/view_registry_test.cc +++ b/sdk/test/metrics/view_registry_test.cc @@ -8,6 +8,10 @@ #include +#if defined(OPENTELEMETRY_HAVE_WORKING_REGEX) +# include +#endif + using namespace opentelemetry::sdk::metrics; using namespace opentelemetry::sdk::instrumentationscope; @@ -28,14 +32,14 @@ TEST(ViewRegistry, FindViewsEmptyRegistry) registry.FindViews(default_instrument_descriptor, *default_instrumentation_scope.get(), [&count](const View &view) { count++; -#if HAVE_WORKING_REGEX +#if OPENTELEMETRY_HAVE_WORKING_REGEX EXPECT_EQ(view.GetName(), ""); EXPECT_EQ(view.GetDescription(), ""); #endif EXPECT_EQ(view.GetAggregationType(), AggregationType::kDefault); return true; }); -#if HAVE_WORKING_REGEX +#if OPENTELEMETRY_HAVE_WORKING_REGEX EXPECT_EQ(count, 1); EXPECT_EQ(status, true); #endif @@ -73,13 +77,13 @@ TEST(ViewRegistry, FindNonExistingView) registry.FindViews(default_instrument_descriptor, *default_instrumentation_scope.get(), [&count, &view_name, &view_description](const View &view) { count++; -#if HAVE_WORKING_REGEX +#if OPENTELEMETRY_HAVE_WORKING_REGEX EXPECT_EQ(view.GetName(), view_name); EXPECT_EQ(view.GetDescription(), view_description); #endif return true; }); -#if HAVE_WORKING_REGEX +#if OPENTELEMETRY_HAVE_WORKING_REGEX EXPECT_EQ(count, 1); EXPECT_EQ(status, true); #endif diff --git a/sdk/test/resource/BUILD b/sdk/test/resource/BUILD index e70f16ee78..145ecf0b56 100644 --- a/sdk/test/resource/BUILD +++ b/sdk/test/resource/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + cc_test( name = "resource_test", srcs = [ diff --git a/sdk/test/resource/CMakeLists.txt b/sdk/test/resource/CMakeLists.txt index 514b98680b..dfe78589f8 100644 --- a/sdk/test/resource/CMakeLists.txt +++ b/sdk/test/resource/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + foreach(testname resource_test) add_executable(${testname} "${testname}.cc") target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} diff --git a/sdk/test/resource/resource_test.cc b/sdk/test/resource/resource_test.cc index 1c14301a57..803d5666d9 100644 --- a/sdk/test/resource/resource_test.cc +++ b/sdk/test/resource/resource_test.cc @@ -26,7 +26,9 @@ namespace nostd = opentelemetry::nostd; class TestResource : public Resource { public: - TestResource(ResourceAttributes attributes = ResourceAttributes()) : Resource(attributes) {} + TestResource(ResourceAttributes attributes = ResourceAttributes(), std::string schema_url = {}) + : Resource(attributes, schema_url) + {} }; TEST(ResourceTest, create_without_servicename) @@ -170,6 +172,32 @@ TEST(ResourceTest, MergeEmptyString) EXPECT_EQ(received_attributes.size(), expected_attributes.size()); } +TEST(ResourceTest, MergeSchemaUrl) +{ + const std::string url = "https://opentelemetry.io/schemas/v3.1.4"; + + TestResource resource_empty_url({}, ""); + TestResource resource_some_url({}, url); + TestResource resource_different_url({}, "different"); + + // Specified behavior: + auto merged_both_empty = resource_empty_url.Merge(resource_empty_url); + EXPECT_TRUE(merged_both_empty.GetSchemaURL().empty()); + + auto merged_old_empty = resource_empty_url.Merge(resource_some_url); + EXPECT_EQ(merged_old_empty.GetSchemaURL(), url); + + auto merged_updating_empty = resource_some_url.Merge(resource_empty_url); + EXPECT_EQ(merged_updating_empty.GetSchemaURL(), url); + + auto merged_same_url = resource_some_url.Merge(resource_some_url); + EXPECT_EQ(merged_same_url.GetSchemaURL(), url); + + // Implementation-defined behavior: + auto merged_different_url = resource_different_url.Merge(resource_some_url); + EXPECT_EQ(merged_different_url.GetSchemaURL(), url); +} + #ifndef NO_GETENV TEST(ResourceTest, OtelResourceDetector) { diff --git a/sdk/test/trace/BUILD b/sdk/test/trace/BUILD index c00b91484a..9aa8a95cdf 100644 --- a/sdk/test/trace/BUILD +++ b/sdk/test/trace/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark") cc_test( diff --git a/sdk/test/trace/CMakeLists.txt b/sdk/test/trace/CMakeLists.txt index 1e66704e2f..385c8eaacd 100644 --- a/sdk/test/trace/CMakeLists.txt +++ b/sdk/test/trace/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + foreach( testname tracer_provider_test diff --git a/sdk/test/trace/batch_span_processor_test.cc b/sdk/test/trace/batch_span_processor_test.cc index 744d80775d..b7a6558538 100644 --- a/sdk/test/trace/batch_span_processor_test.cc +++ b/sdk/test/trace/batch_span_processor_test.cc @@ -23,11 +23,13 @@ class MockSpanExporter final : public sdk::trace::SpanExporter public: MockSpanExporter( std::shared_ptr>> spans_received, + std::shared_ptr> shut_down_counter, std::shared_ptr> is_shutdown, std::shared_ptr> is_export_completed = std::shared_ptr>(new std::atomic(false)), const std::chrono::milliseconds export_delay = std::chrono::milliseconds(0)) noexcept : spans_received_(spans_received), + shut_down_counter_(shut_down_counter), is_shutdown_(is_shutdown), is_export_completed_(is_export_completed), export_delay_(export_delay) @@ -60,6 +62,12 @@ class MockSpanExporter final : public sdk::trace::SpanExporter return sdk::common::ExportResult::kSuccess; } + bool ForceFlush(std::chrono::microseconds /*timeout*/) noexcept override + { + ++(*shut_down_counter_); + return true; + } + bool Shutdown(std::chrono::microseconds /* timeout */) noexcept override { *is_shutdown_ = true; @@ -70,6 +78,7 @@ class MockSpanExporter final : public sdk::trace::SpanExporter private: std::shared_ptr>> spans_received_; + std::shared_ptr> shut_down_counter_; std::shared_ptr> is_shutdown_; std::shared_ptr> is_export_completed_; // Meant exclusively to test force flush timeout @@ -104,13 +113,15 @@ class BatchSpanProcessorTestPeer : public testing::Test TEST_F(BatchSpanProcessorTestPeer, TestShutdown) { + std::shared_ptr> shut_down_counter(new std::atomic(0)); std::shared_ptr> is_shutdown(new std::atomic(false)); std::shared_ptr>> spans_received( new std::vector>); auto batch_processor = std::shared_ptr(new sdk::trace::BatchSpanProcessor( - std::unique_ptr(new MockSpanExporter(spans_received, is_shutdown)), + std::unique_ptr( + new MockSpanExporter(spans_received, shut_down_counter, is_shutdown)), sdk::trace::BatchSpanProcessorOptions())); const int num_spans = 3; @@ -136,13 +147,15 @@ TEST_F(BatchSpanProcessorTestPeer, TestShutdown) TEST_F(BatchSpanProcessorTestPeer, TestForceFlush) { + std::shared_ptr> shut_down_counter(new std::atomic(0)); std::shared_ptr> is_shutdown(new std::atomic(false)); std::shared_ptr>> spans_received( new std::vector>); auto batch_processor = std::shared_ptr(new sdk::trace::BatchSpanProcessor( - std::unique_ptr(new MockSpanExporter(spans_received, is_shutdown)), + std::unique_ptr( + new MockSpanExporter(spans_received, shut_down_counter, is_shutdown)), sdk::trace::BatchSpanProcessorOptions())); const int num_spans = 2048; @@ -157,6 +170,7 @@ TEST_F(BatchSpanProcessorTestPeer, TestForceFlush) std::this_thread::sleep_for(std::chrono::milliseconds(50)); EXPECT_TRUE(batch_processor->ForceFlush()); + EXPECT_GE(shut_down_counter->load(), 1); EXPECT_EQ(num_spans, spans_received->size()); for (int i = 0; i < num_spans; ++i) @@ -174,7 +188,9 @@ TEST_F(BatchSpanProcessorTestPeer, TestForceFlush) // Give some time to export the spans std::this_thread::sleep_for(std::chrono::milliseconds(50)); + auto shut_down_counter_before = shut_down_counter->load(); EXPECT_TRUE(batch_processor->ForceFlush()); + EXPECT_GT(shut_down_counter->load(), shut_down_counter_before); EXPECT_EQ(num_spans * 2, spans_received->size()); for (int i = 0; i < num_spans; ++i) @@ -209,6 +225,7 @@ TEST_F(BatchSpanProcessorTestPeer, TestManySpansLoss) auto log_handler = nostd::shared_ptr(new MockLogHandler()); sdk::common::internal_log::GlobalLogHandler::SetLogHandler(log_handler); + std::shared_ptr> shut_down_counter(new std::atomic(0)); std::shared_ptr> is_shutdown(new std::atomic(false)); std::shared_ptr>> spans_received( new std::vector>); @@ -217,7 +234,8 @@ TEST_F(BatchSpanProcessorTestPeer, TestManySpansLoss) auto batch_processor = std::shared_ptr(new sdk::trace::BatchSpanProcessor( - std::unique_ptr(new MockSpanExporter(spans_received, is_shutdown)), + std::unique_ptr( + new MockSpanExporter(spans_received, shut_down_counter, is_shutdown)), sdk::trace::BatchSpanProcessorOptions())); auto test_spans = GetTestSpans(batch_processor, max_queue_size); @@ -259,6 +277,7 @@ TEST_F(BatchSpanProcessorTestPeer, TestManySpansLossLess) { /* Test that no spans are lost when sending max_queue_size spans */ + std::shared_ptr> shut_down_counter(new std::atomic(0)); std::shared_ptr> is_shutdown(new std::atomic(false)); std::shared_ptr>> spans_received( new std::vector>); @@ -267,7 +286,8 @@ TEST_F(BatchSpanProcessorTestPeer, TestManySpansLossLess) auto batch_processor = std::shared_ptr(new sdk::trace::BatchSpanProcessor( - std::unique_ptr(new MockSpanExporter(spans_received, is_shutdown)), + std::unique_ptr( + new MockSpanExporter(spans_received, shut_down_counter, is_shutdown)), sdk::trace::BatchSpanProcessorOptions())); auto test_spans = GetTestSpans(batch_processor, num_spans); @@ -294,6 +314,7 @@ TEST_F(BatchSpanProcessorTestPeer, TestScheduleDelayMillis) /* Test that max_export_batch_size spans are exported every schedule_delay_millis seconds */ + std::shared_ptr> shut_down_counter(new std::atomic(0)); std::shared_ptr> is_shutdown(new std::atomic(false)); std::shared_ptr> is_export_completed(new std::atomic(false)); std::shared_ptr>> spans_received( @@ -305,8 +326,8 @@ TEST_F(BatchSpanProcessorTestPeer, TestScheduleDelayMillis) auto batch_processor = std::shared_ptr(new sdk::trace::BatchSpanProcessor( - std::unique_ptr( - new MockSpanExporter(spans_received, is_shutdown, is_export_completed, export_delay)), + std::unique_ptr(new MockSpanExporter( + spans_received, shut_down_counter, is_shutdown, is_export_completed, export_delay)), options)); auto test_spans = GetTestSpans(batch_processor, max_export_batch_size); diff --git a/sdk/test/trace/simple_processor_test.cc b/sdk/test/trace/simple_processor_test.cc index e65fd3b29a..7653bb2cfc 100644 --- a/sdk/test/trace/simple_processor_test.cc +++ b/sdk/test/trace/simple_processor_test.cc @@ -17,9 +17,9 @@ using opentelemetry::trace::SpanContext; TEST(SimpleProcessor, ToInMemorySpanExporter) { - std::unique_ptr exporter(new InMemorySpanExporter()); + InMemorySpanExporter *exporter = new InMemorySpanExporter(); std::shared_ptr span_data = exporter->GetData(); - SimpleSpanProcessor processor(std::move(exporter)); + SimpleSpanProcessor processor(std::unique_ptr{exporter}); auto recordable = processor.MakeRecordable(); @@ -38,7 +38,9 @@ TEST(SimpleProcessor, ToInMemorySpanExporter) class RecordShutdownExporter final : public SpanExporter { public: - RecordShutdownExporter(int *shutdown_counter) : shutdown_counter_(shutdown_counter) {} + RecordShutdownExporter(int *force_flush_counter, int *shutdown_counter) + : force_flush_counter_(force_flush_counter), shutdown_counter_(shutdown_counter) + {} std::unique_ptr MakeRecordable() noexcept override { @@ -51,6 +53,12 @@ class RecordShutdownExporter final : public SpanExporter return ExportResult::kSuccess; } + bool ForceFlush(std::chrono::microseconds /* timeout */) noexcept override + { + *force_flush_counter_ += 1; + return true; + } + bool Shutdown(std::chrono::microseconds /* timeout */) noexcept override { *shutdown_counter_ += 1; @@ -58,17 +66,70 @@ class RecordShutdownExporter final : public SpanExporter } private: + int *force_flush_counter_; int *shutdown_counter_; }; TEST(SimpleSpanProcessor, ShutdownCalledOnce) { - int shutdowns = 0; - std::unique_ptr exporter(new RecordShutdownExporter(&shutdowns)); - SimpleSpanProcessor processor(std::move(exporter)); + int force_flush = 0; + int shutdowns = 0; + RecordShutdownExporter *exporter = new RecordShutdownExporter(&force_flush, &shutdowns); + SimpleSpanProcessor processor(std::unique_ptr{exporter}); EXPECT_EQ(0, shutdowns); processor.Shutdown(); EXPECT_EQ(1, shutdowns); processor.Shutdown(); EXPECT_EQ(1, shutdowns); + + EXPECT_EQ(0, force_flush); +} + +TEST(SimpleSpanProcessor, ForceFlush) +{ + int force_flush = 0; + int shutdowns = 0; + RecordShutdownExporter *exporter = new RecordShutdownExporter(&force_flush, &shutdowns); + SimpleSpanProcessor processor(std::unique_ptr{exporter}); + processor.ForceFlush(); + EXPECT_EQ(0, shutdowns); + EXPECT_EQ(1, force_flush); + processor.ForceFlush(); + EXPECT_EQ(2, force_flush); +} + +// An exporter that does nothing but record (and give back ) the # of times Shutdown was called. +class FailShutDownForceFlushExporter final : public SpanExporter +{ +public: + FailShutDownForceFlushExporter() {} + + std::unique_ptr MakeRecordable() noexcept override + { + return std::unique_ptr(new SpanData()); + } + + ExportResult Export(const opentelemetry::nostd::span> + & /* recordables */) noexcept override + { + return ExportResult::kSuccess; + } + + bool ForceFlush(std::chrono::microseconds /* timeout */) noexcept override { return false; } + + bool Shutdown(std::chrono::microseconds /* timeout */) noexcept override { return false; } +}; + +TEST(SimpleSpanProcessor, ShutdownFail) +{ + SimpleSpanProcessor processor( + std::unique_ptr{new FailShutDownForceFlushExporter()}); + EXPECT_EQ(false, processor.Shutdown()); +} + +TEST(SimpleSpanProcessor, ForceFlushFail) +{ + SimpleSpanProcessor processor( + std::unique_ptr{new FailShutDownForceFlushExporter()}); + EXPECT_EQ(false, processor.ForceFlush()); } diff --git a/sdk/test/trace/tracer_test.cc b/sdk/test/trace/tracer_test.cc index 3287b39e5d..f92c0f6e93 100644 --- a/sdk/test/trace/tracer_test.cc +++ b/sdk/test/trace/tracer_test.cc @@ -114,9 +114,9 @@ std::shared_ptr initTracer( TEST(Tracer, ToInMemorySpanExporter) { - std::unique_ptr exporter(new InMemorySpanExporter()); + InMemorySpanExporter *exporter = new InMemorySpanExporter(); std::shared_ptr span_data = exporter->GetData(); - auto tracer = initTracer(std::move(exporter)); + auto tracer = initTracer(std::unique_ptr{exporter}); auto span_first = tracer->StartSpan("span 1"); auto scope_first = tracer->WithActiveSpan(span_first); @@ -149,9 +149,9 @@ TEST(Tracer, ToInMemorySpanExporter) TEST(Tracer, StartSpanSampleOn) { - std::unique_ptr exporter(new InMemorySpanExporter()); + InMemorySpanExporter *exporter = new InMemorySpanExporter(); std::shared_ptr span_data = exporter->GetData(); - auto tracer_on = initTracer(std::move(exporter)); + auto tracer_on = initTracer(std::unique_ptr{exporter}); tracer_on->StartSpan("span 1")->End(); @@ -165,9 +165,9 @@ TEST(Tracer, StartSpanSampleOn) TEST(Tracer, StartSpanSampleOff) { - std::unique_ptr exporter(new InMemorySpanExporter()); + InMemorySpanExporter *exporter = new InMemorySpanExporter(); std::shared_ptr span_data = exporter->GetData(); - auto tracer_off = initTracer(std::move(exporter), new AlwaysOffSampler()); + auto tracer_off = initTracer(std::unique_ptr{exporter}, new AlwaysOffSampler()); // This span will not be recorded. auto span = tracer_off->StartSpan("span 2"); @@ -185,10 +185,11 @@ TEST(Tracer, StartSpanSampleOff) TEST(Tracer, StartSpanCustomIdGenerator) { - IdGenerator *id_generator = new MockIdGenerator(); - std::unique_ptr exporter(new InMemorySpanExporter()); + IdGenerator *id_generator = new MockIdGenerator(); + InMemorySpanExporter *exporter = new InMemorySpanExporter(); std::shared_ptr span_data = exporter->GetData(); - auto tracer = initTracer(std::move(exporter), new AlwaysOnSampler(), id_generator); + auto tracer = + initTracer(std::unique_ptr{exporter}, new AlwaysOnSampler(), id_generator); tracer->StartSpan("span 1")->End(); auto spans = span_data->GetSpans(); @@ -200,9 +201,9 @@ TEST(Tracer, StartSpanCustomIdGenerator) TEST(Tracer, StartSpanWithOptionsTime) { - std::unique_ptr exporter(new InMemorySpanExporter()); + InMemorySpanExporter *exporter = new InMemorySpanExporter(); std::shared_ptr span_data = exporter->GetData(); - auto tracer = initTracer(std::move(exporter)); + auto tracer = initTracer(std::unique_ptr{exporter}); opentelemetry::trace::StartSpanOptions start; start.start_system_time = SystemTimestamp(std::chrono::nanoseconds(300)); @@ -223,9 +224,9 @@ TEST(Tracer, StartSpanWithOptionsTime) TEST(Tracer, StartSpanWithAttributes) { - std::unique_ptr exporter(new InMemorySpanExporter()); + InMemorySpanExporter *exporter = new InMemorySpanExporter(); std::shared_ptr span_data = exporter->GetData(); - auto tracer = initTracer(std::move(exporter)); + auto tracer = initTracer(std::unique_ptr{exporter}); // Start a span with all supported scalar attribute types. tracer @@ -271,11 +272,11 @@ TEST(Tracer, StartSpanWithAttributes) ASSERT_EQ(9, cur_span_data->GetAttributes().size()); ASSERT_EQ(314159, nostd::get(cur_span_data->GetAttributes().at("attr1"))); ASSERT_EQ(false, nostd::get(cur_span_data->GetAttributes().at("attr2"))); - ASSERT_EQ(314159, nostd::get(cur_span_data->GetAttributes().at("attr3"))); + ASSERT_EQ((uint32_t)314159, nostd::get(cur_span_data->GetAttributes().at("attr3"))); ASSERT_EQ(-20, nostd::get(cur_span_data->GetAttributes().at("attr4"))); - ASSERT_EQ(20, nostd::get(cur_span_data->GetAttributes().at("attr5"))); + ASSERT_EQ((uint32_t)20, nostd::get(cur_span_data->GetAttributes().at("attr5"))); ASSERT_EQ(-20, nostd::get(cur_span_data->GetAttributes().at("attr6"))); - ASSERT_EQ(20, nostd::get(cur_span_data->GetAttributes().at("attr7"))); + ASSERT_EQ((uint64_t)20, nostd::get(cur_span_data->GetAttributes().at("attr7"))); ASSERT_EQ(3.1, nostd::get(cur_span_data->GetAttributes().at("attr8"))); ASSERT_EQ("string", nostd::get(cur_span_data->GetAttributes().at("attr9"))); @@ -303,9 +304,9 @@ TEST(Tracer, StartSpanWithAttributes) TEST(Tracer, StartSpanWithAttributesCopy) { - std::unique_ptr exporter(new InMemorySpanExporter()); + InMemorySpanExporter *exporter = new InMemorySpanExporter(); std::shared_ptr span_data = exporter->GetData(); - auto tracer = initTracer(std::move(exporter)); + auto tracer = initTracer(std::unique_ptr{exporter}); { std::unique_ptr> numbers(new std::vector); @@ -371,9 +372,9 @@ TEST(Tracer, GetSampler) TEST(Tracer, SpanSetAttribute) { - std::unique_ptr exporter(new InMemorySpanExporter()); + InMemorySpanExporter *exporter = new InMemorySpanExporter(); std::shared_ptr span_data = exporter->GetData(); - auto tracer = initTracer(std::move(exporter)); + auto tracer = initTracer(std::unique_ptr{exporter}); auto span = tracer->StartSpan("span 1"); @@ -389,9 +390,9 @@ TEST(Tracer, SpanSetAttribute) TEST(Tracer, TestAfterEnd) { - std::unique_ptr exporter(new InMemorySpanExporter()); + InMemorySpanExporter *exporter = new InMemorySpanExporter(); std::shared_ptr span_data = exporter->GetData(); - auto tracer = initTracer(std::move(exporter)); + auto tracer = initTracer(std::unique_ptr{exporter}); auto span = tracer->StartSpan("span 1"); span->SetAttribute("abc", 3.1); @@ -417,9 +418,9 @@ TEST(Tracer, TestAfterEnd) TEST(Tracer, SpanSetEvents) { - std::unique_ptr exporter(new InMemorySpanExporter()); + InMemorySpanExporter *exporter = new InMemorySpanExporter(); std::shared_ptr span_data = exporter->GetData(); - auto tracer = initTracer(std::move(exporter)); + auto tracer = initTracer(std::unique_ptr{exporter}); auto span = tracer->StartSpan("span 1"); span->AddEvent("event 1"); @@ -442,9 +443,9 @@ TEST(Tracer, SpanSetEvents) TEST(Tracer, SpanSetLinks) { - std::unique_ptr exporter(new InMemorySpanExporter()); + InMemorySpanExporter *exporter = new InMemorySpanExporter(); std::shared_ptr span_data = exporter->GetData(); - auto tracer = initTracer(std::move(exporter)); + auto tracer = initTracer(std::unique_ptr{exporter}); { @@ -519,9 +520,9 @@ TEST(Tracer, SpanSetLinks) TEST(Tracer, TestAlwaysOnSampler) { - std::unique_ptr exporter(new InMemorySpanExporter()); + InMemorySpanExporter *exporter = new InMemorySpanExporter(); std::shared_ptr span_data = exporter->GetData(); - auto tracer_on = initTracer(std::move(exporter)); + auto tracer_on = initTracer(std::unique_ptr{exporter}); // Testing AlwaysOn sampler. // Create two spans for each tracer. Check the exported result. @@ -538,9 +539,9 @@ TEST(Tracer, TestAlwaysOnSampler) TEST(Tracer, TestAlwaysOffSampler) { - std::unique_ptr exporter(new InMemorySpanExporter()); + InMemorySpanExporter *exporter = new InMemorySpanExporter(); std::shared_ptr span_data = exporter->GetData(); - auto tracer_off = initTracer(std::move(exporter), new AlwaysOffSampler()); + auto tracer_off = initTracer(std::unique_ptr{exporter}, new AlwaysOffSampler()); auto span_off_1 = tracer_off->StartSpan("span 1"); auto span_off_2 = tracer_off->StartSpan("span 2"); @@ -557,10 +558,10 @@ TEST(Tracer, TestParentBasedSampler) { // Current ShouldSample always pass an empty ParentContext, // so this sampler will work as an AlwaysOnSampler. - std::unique_ptr exporter(new InMemorySpanExporter()); + InMemorySpanExporter *exporter = new InMemorySpanExporter(); std::shared_ptr span_data_parent_on = exporter->GetData(); - auto tracer_parent_on = - initTracer(std::move(exporter), new ParentBasedSampler(std::make_shared())); + auto tracer_parent_on = initTracer(std::unique_ptr{exporter}, + new ParentBasedSampler(std::make_shared())); auto span_parent_on_1 = tracer_parent_on->StartSpan("span 1"); auto span_parent_on_2 = tracer_parent_on->StartSpan("span 2"); @@ -577,10 +578,10 @@ TEST(Tracer, TestParentBasedSampler) // Current ShouldSample always pass an empty ParentContext, // so this sampler will work as an AlwaysOnSampler. - std::unique_ptr exporter2(new InMemorySpanExporter()); + InMemorySpanExporter *exporter2 = new InMemorySpanExporter(); std::shared_ptr span_data_parent_off = exporter2->GetData(); auto tracer_parent_off = - initTracer(std::move(exporter2), + initTracer(std::unique_ptr{exporter2}, // Add this to avoid different results for old and new version of clang-format new ParentBasedSampler(std::make_shared())); @@ -596,9 +597,9 @@ TEST(Tracer, TestParentBasedSampler) TEST(Tracer, WithActiveSpan) { - std::unique_ptr exporter(new InMemorySpanExporter()); + InMemorySpanExporter *exporter = new InMemorySpanExporter(); std::shared_ptr span_data = exporter->GetData(); - auto tracer = initTracer(std::move(exporter)); + auto tracer = initTracer(std::unique_ptr{exporter}); auto spans = span_data.get()->GetSpans(); ASSERT_EQ(0, spans.size()); @@ -631,9 +632,9 @@ TEST(Tracer, WithActiveSpan) TEST(Tracer, ExpectParent) { - std::unique_ptr exporter(new InMemorySpanExporter()); + InMemorySpanExporter *exporter = new InMemorySpanExporter(); std::shared_ptr span_data = exporter->GetData(); - auto tracer = initTracer(std::move(exporter)); + auto tracer = initTracer(std::unique_ptr{exporter}); auto spans = span_data.get()->GetSpans(); ASSERT_EQ(0, spans.size()); @@ -666,9 +667,9 @@ TEST(Tracer, ExpectParent) TEST(Tracer, ExpectParentAsContext) { - std::unique_ptr exporter(new InMemorySpanExporter()); + InMemorySpanExporter *exporter = new InMemorySpanExporter(); std::shared_ptr span_data = exporter->GetData(); - auto tracer = initTracer(std::move(exporter)); + auto tracer = initTracer(std::unique_ptr{exporter}); auto spans = span_data.get()->GetSpans(); ASSERT_EQ(0, spans.size()); @@ -704,9 +705,9 @@ TEST(Tracer, ExpectParentAsContext) TEST(Tracer, ValidTraceIdToSampler) { - std::unique_ptr exporter(new InMemorySpanExporter()); + InMemorySpanExporter *exporter = new InMemorySpanExporter(); std::shared_ptr span_data = exporter->GetData(); - auto tracer = initTracer(std::move(exporter), new MockSampler()); + auto tracer = initTracer(std::unique_ptr{exporter}); auto span = tracer->StartSpan("span 1"); // sampler was fed with valid trace_id, so span shouldn't be NoOp Span. @@ -716,9 +717,9 @@ TEST(Tracer, ValidTraceIdToSampler) TEST(Tracer, SpanCleanupWithScope) { - std::unique_ptr exporter(new InMemorySpanExporter()); + InMemorySpanExporter *exporter = new InMemorySpanExporter(); std::shared_ptr span_data = exporter->GetData(); - auto tracer = initTracer(std::move(exporter)); + auto tracer = initTracer(std::unique_ptr{exporter}, new MockSampler()); { auto span0 = tracer->StartSpan("Span0"); auto span1 = tracer->StartSpan("span1"); diff --git a/test_common/BUILD b/test_common/BUILD index cc62431b53..b19ae921e5 100644 --- a/test_common/BUILD +++ b/test_common/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + package(default_visibility = ["//visibility:public"]) cc_library( diff --git a/test_common/CMakeLists.txt b/test_common/CMakeLists.txt index 0ef4b9dab0..5e939bae2e 100644 --- a/test_common/CMakeLists.txt +++ b/test_common/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + if(BUILD_TESTING) add_library(opentelemetry_test_common INTERFACE) target_include_directories( diff --git a/test_common/include/opentelemetry/test_common/ext/http/client/nosend/http_client_nosend.h b/test_common/include/opentelemetry/test_common/ext/http/client/nosend/http_client_nosend.h index 4325885a96..7a6fadbd11 100644 --- a/test_common/include/opentelemetry/test_common/ext/http/client/nosend/http_client_nosend.h +++ b/test_common/include/opentelemetry/test_common/ext/http/client/nosend/http_client_nosend.h @@ -37,6 +37,13 @@ class Request : public opentelemetry::ext::http::client::Request method_ = method; } +# ifdef ENABLE_HTTP_SSL_PREVIEW + void SetSslOptions(const HttpSslOptions &ssl_options) noexcept override + { + ssl_options_ = ssl_options; + } +# endif /* ENABLE_HTTP_SSL_PREVIEW */ + void SetBody(opentelemetry::ext::http::client::Body &body) noexcept override { body_ = std::move(body); @@ -59,6 +66,9 @@ class Request : public opentelemetry::ext::http::client::Request public: opentelemetry::ext::http::client::Method method_; +# ifdef ENABLE_HTTP_SSL_PREVIEW + opentelemetry::ext::http::client::HttpSslOptions ssl_options_; +# endif /* ENABLE_HTTP_SSL_PREVIEW */ opentelemetry::ext::http::client::Body body_; opentelemetry::ext::http::client::Headers headers_; std::string uri_; diff --git a/test_common/src/CMakeLists.txt b/test_common/src/CMakeLists.txt index 4b1ee36afa..b4243cafbd 100644 --- a/test_common/src/CMakeLists.txt +++ b/test_common/src/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + if(BUILD_TESTING) add_subdirectory(http/client/nosend) endif() diff --git a/test_common/src/http/client/nosend/BUILD b/test_common/src/http/client/nosend/BUILD index 6053c967f4..7aaf2a61b5 100644 --- a/test_common/src/http/client/nosend/BUILD +++ b/test_common/src/http/client/nosend/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + package(default_visibility = ["//visibility:public"]) cc_library( diff --git a/test_common/src/http/client/nosend/CMakeLists.txt b/test_common/src/http/client/nosend/CMakeLists.txt index 648944abfc..071e109fe5 100644 --- a/test_common/src/http/client/nosend/CMakeLists.txt +++ b/test_common/src/http/client/nosend/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + if(${BUILD_TESTING}) add_library(opentelemetry_http_client_nosend http_client_factory_nosend.cc http_client_nosend.cc) diff --git a/third_party/BUILD b/third_party/BUILD index 5587e125c0..c039f4798a 100644 --- a/third_party/BUILD +++ b/third_party/BUILD @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + licenses(["notice"]) # Apache 2.0 package(default_visibility = ["//:__subpackages__"]) diff --git a/third_party/opentracing-cpp b/third_party/opentracing-cpp new file mode 160000 index 0000000000..06b57f48de --- /dev/null +++ b/third_party/opentracing-cpp @@ -0,0 +1 @@ +Subproject commit 06b57f48ded1fa3bdd3d4346f6ef29e40e08eaf5 diff --git a/third_party_release b/third_party_release index 3362b23db9..7290896c2d 100644 --- a/third_party_release +++ b/third_party_release @@ -1,3 +1,5 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 # # MAINTAINER # @@ -19,5 +21,6 @@ googletest=release-1.12.1 ms-gsl=v3.1.0-67-g6f45293 nlohmann-json=v3.10.5 opentelemetry-proto=v0.19.0 -prometheus-cpp=v1.0.0 +opentracing-cpp=v1.6.0 +prometheus-cpp=v1.1.0 vcpkg=2022.08.15 diff --git a/tools/WORKSPACE b/tools/WORKSPACE index abebe189fa..3e90ba0c4f 100644 --- a/tools/WORKSPACE +++ b/tools/WORKSPACE @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + local_repository( name = "vcpkg", path = "./vcpkg", diff --git a/tools/build-bazel.cmd b/tools/build-bazel.cmd index f73147e3ac..884fe3f0d5 100644 --- a/tools/build-bazel.cmd +++ b/tools/build-bazel.cmd @@ -1,3 +1,6 @@ +REM Copyright The OpenTelemetry Authors +REM SPDX-License-Identifier: Apache-2.0 + pushd "%~dp0" set "PATH=%CD%;%PATH%" cd .. diff --git a/tools/build-benchmark.cmd b/tools/build-benchmark.cmd index 379cb1313a..fca8188061 100644 --- a/tools/build-benchmark.cmd +++ b/tools/build-benchmark.cmd @@ -1,3 +1,6 @@ +REM Copyright The OpenTelemetry Authors +REM SPDX-License-Identifier: Apache-2.0 + @echo off set BUILDTOOLS_VERSION=vs2019 set CMAKE_GEN="Visual Studio 16 2019" diff --git a/tools/build-benchmark.sh b/tools/build-benchmark.sh index 58d92dc860..21d7ec8aec 100755 --- a/tools/build-benchmark.sh +++ b/tools/build-benchmark.sh @@ -1,5 +1,8 @@ #!/usr/bin/env bash +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + # Switch to workspace root directory first DIR="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" WORKSPACE_ROOT=$DIR/.. diff --git a/tools/build-clang-12.cmd b/tools/build-clang-12.cmd index a41c5bb6c1..74864da47e 100644 --- a/tools/build-clang-12.cmd +++ b/tools/build-clang-12.cmd @@ -1,3 +1,6 @@ +REM Copyright The OpenTelemetry Authors +REM SPDX-License-Identifier: Apache-2.0 + @echo off pushd %~dp0 set "PATH=%ProgramFiles%\LLVM-12\bin;%PATH%" diff --git a/tools/build-clang.cmd b/tools/build-clang.cmd index c160fd661b..b721ca4c17 100644 --- a/tools/build-clang.cmd +++ b/tools/build-clang.cmd @@ -1,3 +1,6 @@ +REM Copyright The OpenTelemetry Authors +REM SPDX-License-Identifier: Apache-2.0 + @echo off pushd %~dp0 set "PATH=%ProgramFiles%\LLVM\bin;%PATH%" diff --git a/tools/build-docker.cmd b/tools/build-docker.cmd index eebdcf98c7..452795c19e 100644 --- a/tools/build-docker.cmd +++ b/tools/build-docker.cmd @@ -1,3 +1,6 @@ +REM Copyright The OpenTelemetry Authors +REM SPDX-License-Identifier: Apache-2.0 + @echo off pushd %~dp0 REM Default arguments diff --git a/tools/build-gtest.sh b/tools/build-gtest.sh index e7e786ac48..d4dbf609de 100755 --- a/tools/build-gtest.sh +++ b/tools/build-gtest.sh @@ -1,5 +1,8 @@ #!/usr/bin/env bash +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + # Switch to workspace root directory first DIR="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" WORKSPACE_ROOT=$DIR/.. diff --git a/tools/build-nuget.cmd b/tools/build-nuget.cmd index 647d96e7a6..8045d446e1 100644 --- a/tools/build-nuget.cmd +++ b/tools/build-nuget.cmd @@ -1,3 +1,6 @@ +REM Copyright The OpenTelemetry Authors +REM SPDX-License-Identifier: Apache-2.0 + @echo off pushd "%~dp0" set "PATH=%CD%;%PATH%" diff --git a/tools/build-nuget.ps1 b/tools/build-nuget.ps1 index 39d18ea7ac..31e548e752 100644 --- a/tools/build-nuget.ps1 +++ b/tools/build-nuget.ps1 @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + # Function returns 4-part 'classic' version string from SemVer 2.0 string function GenVer4Part([String] $Version) { diff --git a/tools/build-vcpkg.sh b/tools/build-vcpkg.sh index f4acb009fe..881f4b5402 100755 --- a/tools/build-vcpkg.sh +++ b/tools/build-vcpkg.sh @@ -1,4 +1,8 @@ #!/bin/bash + +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + export PATH=/usr/local/bin:$PATH DIR="$( cd "$(dirname "$0")" >/dev/null 2>&1 diff --git a/tools/build-vs2015.cmd b/tools/build-vs2015.cmd index ed230d1559..ce3f0791a3 100644 --- a/tools/build-vs2015.cmd +++ b/tools/build-vs2015.cmd @@ -1,3 +1,6 @@ +REM Copyright The OpenTelemetry Authors +REM SPDX-License-Identifier: Apache-2.0 + REM Build with Visual Studio 2015 set "PATH=%ProgramFiles(x86)%\MSBuild\14.0\Bin;%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\VC\bin;%PATH%" diff --git a/tools/build-vs2017.cmd b/tools/build-vs2017.cmd index 3a95d9b110..91049a5c0b 100644 --- a/tools/build-vs2017.cmd +++ b/tools/build-vs2017.cmd @@ -1,3 +1,6 @@ +REM Copyright The OpenTelemetry Authors +REM SPDX-License-Identifier: Apache-2.0 + REM Build with Visual Studio 2017 set "BUILDTOOLS_VERSION=vs2017" set ARCH=x64 diff --git a/tools/build-vs2019.cmd b/tools/build-vs2019.cmd index 1b2250d0bd..752604b829 100644 --- a/tools/build-vs2019.cmd +++ b/tools/build-vs2019.cmd @@ -1,3 +1,6 @@ +REM Copyright The OpenTelemetry Authors +REM SPDX-License-Identifier: Apache-2.0 + REM Build with Visual Studio 2019 set "BUILDTOOLS_VERSION=vs2019" set ARCH=x64 diff --git a/tools/build-vs2022.cmd b/tools/build-vs2022.cmd index dcd68676bb..cfe7501133 100644 --- a/tools/build-vs2022.cmd +++ b/tools/build-vs2022.cmd @@ -1,3 +1,6 @@ +REM Copyright The OpenTelemetry Authors +REM SPDX-License-Identifier: Apache-2.0 + REM Build with Visual Studio 2022 set "BUILDTOOLS_VERSION=vs2022" set ARCH=x64 diff --git a/tools/build.cmd b/tools/build.cmd index 5a47d87764..ad18ba2a9a 100644 --- a/tools/build.cmd +++ b/tools/build.cmd @@ -1,3 +1,6 @@ +REM Copyright The OpenTelemetry Authors +REM SPDX-License-Identifier: Apache-2.0 + @echo off REM ########################################################################################## REM # Build SDK with (msvc or clang) + CMake + (MSBuild or Ninja). # diff --git a/tools/build.sh b/tools/build.sh index 9ac4730008..7e4779b9d0 100755 --- a/tools/build.sh +++ b/tools/build.sh @@ -1,4 +1,8 @@ #!/bin/bash + +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + export PATH=/usr/local/bin:$PATH ## diff --git a/tools/check_copyright.sh b/tools/check_copyright.sh new file mode 100755 index 0000000000..69f0298c5e --- /dev/null +++ b/tools/check_copyright.sh @@ -0,0 +1,97 @@ +#!/bin/bash + +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +if [[ ! -e tools/check_copyright.sh ]]; then + echo "This tool must be run from the topmost directory." >&2 + exit 1 +fi + +set -e + +# +# Process input file .copyright-ignore, +# - remove comments +# - remove blank lines +# to create file /tmp/all_ignored +# + +grep -v "^#" < .copyright-ignore | \ +grep -v "^[[:space:]]*$" > /tmp/all_ignored + +# +# Find all files from the repository +# to create file /tmp/all_checked +# + +find . -type f -print | sort -u > /tmp/all_checked + +# +# Filter out /tmp/all_checked, +# remove all ignored patterns from /tmp/all_ignored +# When the pattern is *.md, +# make sure to filter *\.md to avoid hiding *.cmd +# Then, *\.md needs to be escaped to *\\.md, +# to be given to egrep, hence the sed. +# + +while IFS= read -r PATTERN; do + SAFE_PATTERN=`echo "${PATTERN}" | sed "s!\.!\\\\\.!g"` + echo "Filtering out ${SAFE_PATTERN}" + egrep -v "${SAFE_PATTERN}" < /tmp/all_checked > /tmp/all_checked-tmp + mv /tmp/all_checked-tmp /tmp/all_checked +done < /tmp/all_ignored + +# +# For all files in /tmp/all_checked +# - verify there is copyright +# - verify there is a license +# and append to /tmp/all_missing +# +# Valid copyright strings are: +# - Copyright The OpenTelemetry Authors +# +# Valid license strings are: +# - SPDX-License-Identifier: Apache-2.0 +# + +rm -rf /tmp/all_missing +touch /tmp/all_missing + +for FILE in `cat /tmp/all_checked` +do + echo "Checking ${FILE}" + export COPYRIGHT=`head -10 ${FILE} | grep -c "Copyright The OpenTelemetry Authors"` + export LICENSE=`head -10 ${FILE} | grep -c "SPDX-License-Identifier: Apache-2.0"` + if [ "$COPYRIGHT" == "0" ]; then + echo "Missing copyright in ${FILE}" >> /tmp/all_missing + fi; + if [ "${LICENSE}" == "0" ]; then + echo "Missing license in ${FILE}" >> /tmp/all_missing + fi; +done + +# +# Final report +# + +FAIL_COUNT=`wc -l < /tmp/all_missing` + +if [ ${FAIL_COUNT} != "0" ]; then + # + # CI FAILED + # + + cat /tmp/all_missing + + echo "Total number of failed checks: ${FAIL_COUNT}" + exit 1 +fi; + +# +# CI PASSED +# + +exit 0 + diff --git a/tools/download.cmd b/tools/download.cmd index 55820b6815..266149f47e 100644 --- a/tools/download.cmd +++ b/tools/download.cmd @@ -1,3 +1,6 @@ +REM Copyright The OpenTelemetry Authors +REM SPDX-License-Identifier: Apache-2.0 + @REM This script allows to download a file to local machine. First argument is URL set "PATH=%SystemRoot%;%SystemRoot%\System32;%SystemRoot%\System32\WindowsPowerShell\v1.0\;%ProgramFiles%\Git\bin" @powershell -File Download.ps1 %1 diff --git a/tools/download.ps1 b/tools/download.ps1 index c759601aea..eadd46725f 100644 --- a/tools/download.ps1 +++ b/tools/download.ps1 @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + $url=$args[0] $arr=$args[0].Split("/") $fileName=$arr[$arr.Count-1] diff --git a/tools/format.sh b/tools/format.sh index 48714e9a74..2c16204acb 100755 --- a/tools/format.sh +++ b/tools/format.sh @@ -1,4 +1,8 @@ #!/bin/bash + +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + if [[ ! -e tools/format.sh ]]; then echo "This tool must be run from the topmost directory." >&2 exit 1 diff --git a/tools/git-cl.cmd b/tools/git-cl.cmd index f48a15f239..bb25f26d1a 100644 --- a/tools/git-cl.cmd +++ b/tools/git-cl.cmd @@ -1,3 +1,6 @@ +REM Copyright The OpenTelemetry Authors +REM SPDX-License-Identifier: Apache-2.0 + @echo off setlocal enabledelayedexpansion if "%1" == "format" ( diff --git a/tools/git-cl.sh b/tools/git-cl.sh index 5f0cca9e1b..4dcab6da67 100755 --- a/tools/git-cl.sh +++ b/tools/git-cl.sh @@ -1,4 +1,8 @@ #!/bin/sh + +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + if [ "format" = "$1" ]; then if [ -z "$2" ]; then echo Please specify file name. diff --git a/tools/install-vs-addons.cmd b/tools/install-vs-addons.cmd index e6cb0b9a65..8ae592ec33 100644 --- a/tools/install-vs-addons.cmd +++ b/tools/install-vs-addons.cmd @@ -1,3 +1,6 @@ +REM Copyright The OpenTelemetry Authors +REM SPDX-License-Identifier: Apache-2.0 + set "PATH=%SystemRoot%;%SystemRoot%\System32;%SystemRoot%\System32\WindowsPowerShell\v1.0\;%ProgramFiles%\Git\bin" cd %~dp0 call powershell -File .\install_llvm-win64.ps1 diff --git a/tools/install.sh b/tools/install.sh index b034750b74..831c81407c 100755 --- a/tools/install.sh +++ b/tools/install.sh @@ -1,4 +1,8 @@ #!/bin/bash + +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + DIR="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" WORKSPACE_ROOT=$DIR/.. pushd $WORKSPACE_ROOT diff --git a/tools/install_llvm-win32.ps1 b/tools/install_llvm-win32.ps1 index 89b697f400..27345a97e8 100644 --- a/tools/install_llvm-win32.ps1 +++ b/tools/install_llvm-win32.ps1 @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + $llvmVersion = "10.0.0" Write-Host "Installing LLVM $llvmVersion ..." -ForegroundColor Cyan Write-Host "Downloading..." diff --git a/tools/install_llvm-win64.ps1 b/tools/install_llvm-win64.ps1 index d4a2379fa2..35ab643511 100644 --- a/tools/install_llvm-win64.ps1 +++ b/tools/install_llvm-win64.ps1 @@ -1,3 +1,6 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + $llvmVersion = "10.0.0" Write-Host "Installing LLVM $llvmVersion ..." -ForegroundColor Cyan Write-Host "Downloading..." diff --git a/tools/setup-buildtools-mac.sh b/tools/setup-buildtools-mac.sh index dab077976c..a7af1d69fa 100755 --- a/tools/setup-buildtools-mac.sh +++ b/tools/setup-buildtools-mac.sh @@ -1,5 +1,9 @@ #!/bin/sh +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + + # TODO: it's not ideal experience, but we use have to use brew-provided deps. # Sometimes we might run into a situation where a different user takes over # control of the brew dirs. That causes the brew update to fail. diff --git a/tools/setup-buildtools.cmd b/tools/setup-buildtools.cmd index fab61a520e..43be03a267 100644 --- a/tools/setup-buildtools.cmd +++ b/tools/setup-buildtools.cmd @@ -1,3 +1,6 @@ +REM Copyright The OpenTelemetry Authors +REM SPDX-License-Identifier: Apache-2.0 + @echo off setlocal enableextensions setlocal enabledelayedexpansion diff --git a/tools/setup-buildtools.sh b/tools/setup-buildtools.sh index 30e10fb5a5..bcba7b0279 100755 --- a/tools/setup-buildtools.sh +++ b/tools/setup-buildtools.sh @@ -1,5 +1,8 @@ #!/bin/bash +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + # Switch to workspace root directory first DIR="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" diff --git a/tools/setup-cfssl.sh b/tools/setup-cfssl.sh new file mode 100755 index 0000000000..0a4303ce3e --- /dev/null +++ b/tools/setup-cfssl.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +set -e + +[ -z "${CFSSL_VERSION}" ] && export CFSSL_VERSION="1.6.3" + +curl -s -L -o /bin/cfssl https://github.com/cloudflare/cfssl/releases/download/v${CFSSL_VERSION}/cfssl_${CFSSL_VERSION}_linux_amd64 +curl -s -L -o /bin/cfssljson https://github.com/cloudflare/cfssl/releases/download/v${CFSSL_VERSION}/cfssljson_${CFSSL_VERSION}_linux_amd64 +chmod +x /bin/cfssl +chmod +x /bin/cfssljson diff --git a/tools/setup-cmake.sh b/tools/setup-cmake.sh index 522b44bc65..b346653828 100755 --- a/tools/setup-cmake.sh +++ b/tools/setup-cmake.sh @@ -1,4 +1,8 @@ #!/bin/bash + +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + # # This script installs latest CMake on Linux machine # diff --git a/tools/setup-devenv.cmd b/tools/setup-devenv.cmd index 44808997ce..e6088c2d31 100644 --- a/tools/setup-devenv.cmd +++ b/tools/setup-devenv.cmd @@ -1,3 +1,6 @@ +REM Copyright The OpenTelemetry Authors +REM SPDX-License-Identifier: Apache-2.0 + endlocal set "PATH=%~dp0;%PATH%" set "TOOLS_PATH=%~dp0" diff --git a/tools/setup-devenv.sh b/tools/setup-devenv.sh index b851e211a7..b3c84dd723 100755 --- a/tools/setup-devenv.sh +++ b/tools/setup-devenv.sh @@ -1,5 +1,8 @@ #!/bin/sh +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + # Try to autodetect the tools dir if [ "$BASH_SOURCE" != "" ]; then TOOLS_PATH=`dirname ${BASH_SOURCE[0]}` diff --git a/tools/setup-ninja.sh b/tools/setup-ninja.sh index fe3fe9cdfc..be69bd0cc8 100755 --- a/tools/setup-ninja.sh +++ b/tools/setup-ninja.sh @@ -1,4 +1,8 @@ #!/bin/bash + +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + # TODO: add support for Ninja on Mac OS X wget -O /tmp/ninja.zip https://github.com/ninja-build/ninja/releases/download/v1.10.1/ninja-linux.zip sudo unzip /tmp/ninja.zip -d /usr/local/bin/ diff --git a/tools/setup-protobuf.sh b/tools/setup-protobuf.sh index f6f0fb4535..2549c5aa8e 100755 --- a/tools/setup-protobuf.sh +++ b/tools/setup-protobuf.sh @@ -1,4 +1,8 @@ #!/bin/bash + +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + pushd /tmp curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v3.14.0/protoc-3.14.0-linux-x86_64.zip unzip -o protoc-3.14.0-linux-x86_64.zip -d /usr/local/ diff --git a/tools/vcvars.cmd b/tools/vcvars.cmd index 9023b8cd78..5b78a1706d 100644 --- a/tools/vcvars.cmd +++ b/tools/vcvars.cmd @@ -1,3 +1,6 @@ +REM Copyright The OpenTelemetry Authors +REM SPDX-License-Identifier: Apache-2.0 + @echo off REM +-------------------------------------------------------------------+ REM | Autodetect and set up the build environment. |