├── ci ├── BUILD ├── install_osx_cmake.sh ├── install_osx_bazelisk.sh ├── clang-tidy-wrapper.sh ├── install_cares.sh ├── install_libevent.sh ├── Dockerfile ├── gen_compilation_database.sh ├── install_benchmark.sh ├── install_opentracing.sh ├── run_lightstep_docker.sh ├── install_clang.sh ├── setup_windows_build_environment.ps1 ├── install_grpc.sh ├── install_bazel.sh ├── install_protobuf.sh ├── install_cmake.ps1 ├── setup_build_environment.sh ├── clone_lightstep_benchmarks.sh ├── do_ci.ps1 ├── release.sh ├── run_clang_tidy.sh └── fix_compilation_database.py ├── .gitmodules ├── lightstep-tracer-common ├── WORKSPACE ├── third_party │ ├── googleapis │ │ ├── WORKSPACE │ │ ├── README.lightstep-tracer-common │ │ └── google │ │ │ └── api │ │ │ └── annotations.proto │ └── protobuf │ │ └── README.lightstep-tracer-common ├── circle.yml ├── README.lightstep-tracer-cpp ├── lightstep_carrier.proto └── BUILD ├── .clang-tidy ├── bridge └── python │ ├── requirements.txt │ ├── wheel │ ├── __init__.py │ ├── WHEEL.in │ └── generate_record.py │ ├── lightstep-export-map.ld │ ├── binary │ ├── py3 │ │ ├── lightstep-export-map.ld │ │ └── BUILD │ ├── py27m │ │ ├── lightstep-export-map.ld │ │ └── BUILD │ └── py27mu │ │ ├── lightstep-export-map.ld │ │ └── BUILD │ └── src │ └── BUILD ├── example ├── CMakeLists.txt ├── stream │ ├── CMakeLists.txt │ ├── BUILD │ └── main.cpp └── tutorial │ ├── CMakeLists.txt │ ├── BUILD │ └── text_map_carrier.h ├── doc └── diagram.png ├── version.h.in ├── bazel ├── run_gprof2dot.py ├── glibc_version.cpp ├── graphviz.BUILD ├── cares.BUILD ├── valgrind.BUILD ├── libevent.BUILD ├── profile_benchmark.sh └── BUILD ├── tracer-export-map.ld ├── src ├── common │ ├── platform │ │ ├── memory.h │ │ ├── time.h │ │ ├── utility.h │ │ ├── string_unix.cpp │ │ ├── string_windows.cpp │ │ ├── fork_windows.cpp │ │ ├── fork_unix.cpp │ │ ├── fork.h │ │ ├── string.h │ │ ├── network_environment.h │ │ ├── utility_unix.cpp │ │ ├── utility_windows.cpp │ │ ├── network_environment_unix.cpp │ │ ├── error.h │ │ ├── network_environment_windows.cpp │ │ ├── error_unix.cpp │ │ └── BUILD │ ├── version_check.cpp │ ├── in_memory_stream.h │ ├── noncopyable.h │ ├── spin_lock_mutex.h │ ├── random_traverser.h │ ├── chunked_http_framing.h │ ├── chunked_http_framing.cpp │ ├── buffer_chain.cpp │ ├── in_memory_stream.cpp │ ├── report_request_framing.h │ ├── report_request_framing.cpp │ ├── timestamp.h │ ├── random_traverser.cpp │ ├── fragment_array_input_stream.h │ ├── fragment_input_stream.cpp │ └── logger.cpp ├── tracer │ ├── tag.h │ ├── propagation │ │ ├── b3_propagator.h │ │ ├── lightstep_propagator.h │ │ ├── propagation_options.h │ │ ├── binary_propagation.h │ │ ├── trace_context_propagator.h │ │ ├── b3_propagator.cpp │ │ ├── trace_context.h │ │ ├── lightstep_propagator.cpp │ │ ├── propagator.h │ │ ├── baggage_propagator.h │ │ ├── utility.h │ │ └── envoy_propagator.h │ ├── no_default_ssl_roots_pem.cpp │ ├── tag.cpp │ ├── lightstep_tracer_factory.h │ ├── json_options.h │ ├── baggage_flat_map.h │ ├── counting_metrics_observer.h │ ├── utility.cpp │ ├── lightstep_span_context.cpp │ ├── legacy │ │ └── BUILD │ ├── lightstep_tracer_factory.cpp │ ├── lightstep_span_context.h │ └── dynamic_load.cpp ├── recorder │ ├── grpc_transporter.h │ ├── no_grpc_transporter.cpp │ ├── no_stream_recorder.cpp │ ├── stream_recorder.h │ ├── grpc_transporter │ │ └── BUILD │ ├── transporter.cpp │ ├── serialization │ │ ├── report_request_header.h │ │ ├── embedded_metrics_message.h │ │ ├── BUILD │ │ └── report_request_header.cpp │ ├── stream_recorder │ │ ├── utility.h │ │ ├── status_line_parser.h │ │ ├── host_header.h │ │ ├── span_stream.h │ │ └── satellite_endpoint_manager.h │ ├── report_builder.h │ ├── metrics_tracker.h │ └── manual_recorder.h └── network │ ├── vector_write.h │ ├── ares_dns_resolver │ ├── BUILD │ ├── ares_library_handle.h │ └── ares_dns_resolver.h │ ├── timer_event.cpp │ ├── timer_event.h │ └── socket.h ├── 3rd_party ├── base64 │ ├── README.txt │ ├── BUILD │ └── include │ │ └── lightstep │ │ └── base64 │ │ └── base64.h ├── catch2 │ ├── BUILD │ ├── catch_main.cpp │ └── LICENSE.txt └── CMakeLists.txt ├── scripts └── fix_format.sh ├── test ├── cmake │ ├── CMakeLists.txt │ └── load_tracer_test.cpp ├── common │ ├── test.proto │ ├── chunked_http_framing_test.cpp │ ├── random_test.cpp │ ├── fast_random_number_generator_test.cpp │ ├── function_ref_test.cpp │ ├── spin_lock_mutex_test.cpp │ ├── timestamp_test.cpp │ ├── atomic_unique_ptr_test.cpp │ ├── logger_test.cpp │ ├── report_request_framing_test.cpp │ ├── random_traverser_test.cpp │ ├── direct_coded_output_stream_test.cpp │ ├── flat_map_test.cpp │ ├── fork_id_test.cpp │ ├── circular_buffer_range_test.cpp │ ├── protobuf_test.cpp │ └── composable_fragment_input_stream_test.cpp ├── mock_satellite │ ├── mock_satellite.proto │ ├── mock_satellite_handle.h │ └── mock_satellite_query.cpp ├── ports.h ├── mock_dns_server │ ├── mock_dns_server_handle.h │ └── BUILD ├── bridge │ └── python │ │ ├── BUILD │ │ ├── span_probe.py │ │ └── tracer_test.py ├── mock_dns_resolution_callback.cpp ├── network │ ├── ares_dns_resolver │ │ └── BUILD │ ├── socket_test.cpp │ ├── event_test.cpp │ ├── no_dns_resolver_test.cpp │ ├── ip_address_test.cpp │ └── event_base_test.cpp ├── echo_server │ ├── echo_server_handle.h │ ├── BUILD │ └── echo_server_handle.cpp ├── tracer │ ├── utility_test.cpp │ ├── propagation │ │ ├── http_headers_carrier.h │ │ ├── text_map_carrier.h │ │ ├── lightstep_propagation_test.cpp │ │ └── utility.h │ └── span_probe.cpp ├── recorder │ ├── stream_recorder │ │ ├── host_header_test.cpp │ │ ├── fragment_span_input_stream_test.cpp │ │ ├── utility_test.cpp │ │ ├── stream_recorder_fork_test.cpp │ │ └── status_line_parser_test.cpp │ ├── in_memory_recorder.h │ ├── serialization │ │ ├── report_request_header_test.cpp │ │ ├── embedded_metrics_message_test.cpp │ │ └── BUILD │ ├── in_memory_sync_transporter.cpp │ ├── legacy_in_memory_async_transporter.h │ ├── in_memory_sync_transporter.h │ ├── fork_aware_recorder_test.cpp │ └── in_memory_async_transporter.h ├── string_logger_sink.h ├── child_process_handle.h ├── string_logger_sink.cpp ├── zero_copy_connection_input_stream.h ├── mock_dns_resolution_callback.h ├── composable_fragment_input_stream_wrapper.h ├── number_simulation.h └── baseline_circular_buffer_test.cpp ├── lightstep-tracer-configuration └── BUILD ├── benchmark ├── tracer_upload_bench │ ├── benchmark_report.h │ ├── tracer_upload_bench.proto │ ├── span_drop_counter.h │ ├── span.h │ ├── BUILD │ ├── utility.h │ ├── benchmark_report.cpp │ └── main.cpp └── BUILD ├── .gitignore ├── include └── lightstep │ ├── metrics_observer.h │ ├── binary_carrier.h │ ├── buffer_chain.h │ └── BUILD ├── LICENSE ├── .bazelrc └── cmake └── Modules ├── LightStepTracerConfiguration.cmake └── FindCARES.cmake /ci/BUILD: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lightstep-tracer-common/WORKSPACE: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | Checks: '*' 2 | WarningsAsErrors: '*' 3 | -------------------------------------------------------------------------------- /lightstep-tracer-common/third_party/googleapis/WORKSPACE: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /bridge/python/requirements.txt: -------------------------------------------------------------------------------- 1 | opentracing 2 | gprof2dot 3 | -------------------------------------------------------------------------------- /bridge/python/wheel/__init__.py: -------------------------------------------------------------------------------- 1 | from .lightstep_streaming import Tracer 2 | -------------------------------------------------------------------------------- /ci/install_osx_cmake.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | brew install cmake 6 | -------------------------------------------------------------------------------- /example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(tutorial) 2 | add_subdirectory(stream) 3 | -------------------------------------------------------------------------------- /ci/install_osx_bazelisk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | brew install bazelisk 6 | -------------------------------------------------------------------------------- /bridge/python/lightstep-export-map.ld: -------------------------------------------------------------------------------- 1 | { 2 | global: 3 | Py*; 4 | local: *; 5 | }; 6 | 7 | -------------------------------------------------------------------------------- /doc/diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightstep/lightstep-tracer-cpp/HEAD/doc/diagram.png -------------------------------------------------------------------------------- /version.h.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define LIGHTSTEP_VERSION "${LIGHTSTEP_VERSION_STRING}" 4 | -------------------------------------------------------------------------------- /bazel/run_gprof2dot.py: -------------------------------------------------------------------------------- 1 | from gprof2dot import main 2 | 3 | if __name__ == "__main__": 4 | main() 5 | -------------------------------------------------------------------------------- /tracer-export-map.ld: -------------------------------------------------------------------------------- 1 | { 2 | global: 3 | OpenTracingMakeTracerFactory; 4 | local: *; 5 | }; 6 | -------------------------------------------------------------------------------- /ci/clang-tidy-wrapper.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | clang-tidy-6.0 -warnings-as-errors='*' "$@" 6 | -------------------------------------------------------------------------------- /bridge/python/binary/py3/lightstep-export-map.ld: -------------------------------------------------------------------------------- 1 | { 2 | global: 3 | Py*; 4 | local: *; 5 | }; 6 | 7 | -------------------------------------------------------------------------------- /bridge/python/wheel/WHEEL.in: -------------------------------------------------------------------------------- 1 | Wheel-Version: 1.0 2 | Generator: lightstep_custom (0.1.0) 3 | Root-Is-Purelib: false 4 | -------------------------------------------------------------------------------- /lightstep-tracer-common/circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | services: 3 | - docker 4 | 5 | test: 6 | override: 7 | - make test 8 | -------------------------------------------------------------------------------- /src/common/platform/memory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef _WIN32 4 | #include 5 | #else 6 | #include 7 | #endif 8 | -------------------------------------------------------------------------------- /3rd_party/base64/README.txt: -------------------------------------------------------------------------------- 1 | Copied from Envoy (https://github.com/envoyproxy/envoy). 2 | 3 | commit d70404f7e5c89ab2c5fab72b516e2bf601969557 4 | -------------------------------------------------------------------------------- /bridge/python/binary/py27m/lightstep-export-map.ld: -------------------------------------------------------------------------------- 1 | { 2 | global: 3 | Py*; 4 | initlightstep_streaming; 5 | local: *; 6 | }; 7 | 8 | -------------------------------------------------------------------------------- /bridge/python/binary/py27mu/lightstep-export-map.ld: -------------------------------------------------------------------------------- 1 | { 2 | global: 3 | Py*; 4 | initlightstep_streaming; 5 | local: *; 6 | }; 7 | 8 | -------------------------------------------------------------------------------- /ci/install_cares.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | apt-get install --no-install-recommends --no-install-suggests -y \ 6 | libc-ares-dev 7 | 8 | -------------------------------------------------------------------------------- /ci/install_libevent.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | apt-get install --no-install-recommends --no-install-suggests -y \ 6 | libevent-dev 7 | 8 | -------------------------------------------------------------------------------- /bridge/python/src/BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "//bazel:lightstep_build_system.bzl", 3 | "lightstep_package", 4 | ) 5 | 6 | lightstep_package() 7 | 8 | exports_files(["module.cpp"]) 9 | -------------------------------------------------------------------------------- /example/stream/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if (LIGHTSTEP_USE_STREAMING) 2 | add_executable(stream main.cpp) 3 | target_link_libraries(stream ${LIGHTSTEP_LIBRARY} ${LIGHTSTEP_LINK_LIBRARIES}) 4 | endif() 5 | -------------------------------------------------------------------------------- /example/tutorial/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if (LIGHTSTEP_USE_GRPC) 2 | add_executable(tutorial tutorial.cpp) 3 | target_link_libraries(tutorial ${LIGHTSTEP_LIBRARY} ${LIGHTSTEP_LINK_LIBRARIES}) 4 | endif() 5 | -------------------------------------------------------------------------------- /src/common/platform/time.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef _WIN32 4 | #define WIN32_LEAN_AND_MEAN 5 | #define NOMINMAX 6 | #include 7 | #else 8 | #include 9 | #endif 10 | -------------------------------------------------------------------------------- /src/common/version_check.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static_assert(OPENTRACING_ABI_VERSION[0] == '2', 4 | "Invalid version of OpenTracing. Please install a version using the v2 ABI."); 5 | -------------------------------------------------------------------------------- /scripts/fix_format.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | find . -path ./3rd_party -prune -o \( -name '*.h' -or -name '*.cpp' \) \ 3 | -exec clang-format -i {} \; 4 | find . -path ./3rd_party -prune -o \( -name '*.go' \) \ 5 | -exec go fmt {} \; 6 | -------------------------------------------------------------------------------- /lightstep-tracer-common/README.lightstep-tracer-cpp: -------------------------------------------------------------------------------- 1 | lightstep-tracer-common 2 | ======================= 3 | 4 | Project: lightstep-tracer-common 5 | URL: https://github.com/lightstep/lightstep-tracer-common 6 | Revision: 3943f3f04e3547e7e68d7900ef2efde045fa8901 7 | 8 | -------------------------------------------------------------------------------- /src/common/platform/utility.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace lightstep { 6 | /** 7 | * @return the name of the executable invoked or c++program if unsuccessful. 8 | */ 9 | std::string GetProgramName(); 10 | } // namespace lightstep 11 | -------------------------------------------------------------------------------- /src/common/platform/string_unix.cpp: -------------------------------------------------------------------------------- 1 | #include "common/platform/string.h" 2 | 3 | #include 4 | 5 | namespace lightstep { 6 | int StrCaseCmp(const char* s1, const char* s2) noexcept { 7 | return ::strcasecmp(s1, s2); 8 | } 9 | } // namespace lightstep 10 | -------------------------------------------------------------------------------- /src/common/platform/string_windows.cpp: -------------------------------------------------------------------------------- 1 | #include "common/platform/string.h" 2 | 3 | #include 4 | 5 | namespace lightstep { 6 | int StrCaseCmp(const char* s1, const char* s2) noexcept { 7 | return ::_stricmp(s1, s2); 8 | } 9 | } // namespace lightstep 10 | -------------------------------------------------------------------------------- /src/tracer/tag.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace lightstep { 6 | // Workaround to https://github.com/opentracing/opentracing-cpp/issues/111 7 | extern const opentracing::string_view SamplingPriorityKey; 8 | } // namespace lightstep 9 | -------------------------------------------------------------------------------- /example/stream/BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "//bazel:lightstep_build_system.bzl", 3 | "lightstep_cc_binary", 4 | ) 5 | 6 | lightstep_cc_binary( 7 | name = "stream", 8 | srcs = [ 9 | "main.cpp", 10 | ], 11 | deps = [ 12 | "//:tracer_lib", 13 | ], 14 | ) 15 | -------------------------------------------------------------------------------- /src/common/platform/fork_windows.cpp: -------------------------------------------------------------------------------- 1 | #include "common/platform/fork.h" 2 | 3 | namespace lightstep { 4 | int AtFork(void (*prepare)(), void (*parent)(), void (*child)()) noexcept { 5 | (void)prepare; 6 | (void)parent; 7 | (void)child; 8 | return 0; 9 | } 10 | } // namespace lightstep 11 | -------------------------------------------------------------------------------- /src/tracer/propagation/b3_propagator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "tracer/propagation/propagator.h" 6 | 7 | #include 8 | 9 | namespace lightstep { 10 | std::unique_ptr MakeB3Propagator(); 11 | } // namespace lightstep 12 | -------------------------------------------------------------------------------- /src/common/platform/fork_unix.cpp: -------------------------------------------------------------------------------- 1 | #include "common/platform/fork.h" 2 | 3 | #include 4 | 5 | namespace lightstep { 6 | int AtFork(void (*prepare)(), void (*parent)(), void (*child)()) noexcept { 7 | return ::pthread_atfork(prepare, parent, child); 8 | } 9 | } // namespace lightstep 10 | -------------------------------------------------------------------------------- /src/recorder/grpc_transporter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/logger.h" 4 | #include "lightstep/tracer.h" 5 | 6 | namespace lightstep { 7 | std::unique_ptr MakeGrpcTransporter( 8 | Logger& logger, const LightStepTracerOptions& options); 9 | } // namespace lightstep 10 | -------------------------------------------------------------------------------- /ci/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | WORKDIR /3rd_party 4 | 5 | ADD setup_build_environment.sh /3rd_party 6 | ADD install_bazel.sh /3rd_party 7 | ADD install_clang.sh /3rd_party 8 | 9 | RUN /3rd_party/setup_build_environment.sh \ 10 | && /3rd_party/install_bazel.sh \ 11 | && /3rd_party/install_clang.sh 12 | -------------------------------------------------------------------------------- /example/tutorial/BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "//bazel:lightstep_build_system.bzl", 3 | "lightstep_cc_binary", 4 | ) 5 | 6 | lightstep_cc_binary( 7 | name = "tutorial", 8 | srcs = [ 9 | "text_map_carrier.h", 10 | "tutorial.cpp", 11 | ], 12 | deps = [ 13 | "//:tracer_lib", 14 | ], 15 | ) 16 | 17 | -------------------------------------------------------------------------------- /ci/gen_compilation_database.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | RELEASE_VERSION=0.4.2 4 | 5 | if [[ ! -d bazel-compilation-database-${RELEASE_VERSION} ]]; then 6 | curl -L https://github.com/grailbio/bazel-compilation-database/archive/${RELEASE_VERSION}.tar.gz | tar -xz 7 | fi 8 | 9 | bazel-compilation-database-${RELEASE_VERSION}/generate.sh $@ 10 | -------------------------------------------------------------------------------- /ci/install_benchmark.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | BENCHMARK_VERSION=v1.4.1 6 | git clone -b $BENCHMARK_VERSION https://github.com/google/benchmark.git google-benchmark 7 | cd google-benchmark 8 | mkdir build 9 | cd build 10 | cmake .. -DBENCHMARK_ENABLE_GTEST_TESTS=OFF -DCMAKE_BUILD_TYPE=RELEASE 11 | make 12 | make install 13 | -------------------------------------------------------------------------------- /src/common/platform/fork.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace lightstep { 4 | /** 5 | * Portable wrapper for pthread_atfork. 6 | * See 7 | * https://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_atfork.html 8 | */ 9 | int AtFork(void (*prepare)(), void (*parent)(), void (*child)()) noexcept; 10 | } // namespace lightstep 11 | -------------------------------------------------------------------------------- /src/tracer/no_default_ssl_roots_pem.cpp: -------------------------------------------------------------------------------- 1 | namespace lightstep { 2 | extern const unsigned char default_ssl_roots_pem[]; 3 | extern const int default_ssl_roots_pem_size; 4 | 5 | // Add a single element to appease -Wzero-length-array 6 | const unsigned char default_ssl_roots_pem[] = {'\0'}; 7 | const int default_ssl_roots_pem_size = 0; 8 | } // namespace lightstep 9 | -------------------------------------------------------------------------------- /test/cmake/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if (WITH_DYNAMIC_LOAD AND BUILD_SHARED_LIBS) 2 | add_executable(load_tracer_test load_tracer_test.cpp) 3 | target_link_libraries(load_tracer_test ${OPENTRACING_LIBRARY}) 4 | add_test(load_tracer_test load_tracer_test 5 | ${CMAKE_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}lightstep_tracer${CMAKE_SHARED_LIBRARY_SUFFIX}) 6 | endif() 7 | -------------------------------------------------------------------------------- /test/common/test.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package lightstep.test; 4 | 5 | import "google/protobuf/timestamp.proto"; 6 | import "lightstep-tracer-common/collector.proto"; 7 | 8 | message KeyValueTest { 9 | lightstep.collector.KeyValue key_value = 1; 10 | } 11 | 12 | message TimestampTest { 13 | google.protobuf.Timestamp timestamp = 1; 14 | } 15 | -------------------------------------------------------------------------------- /src/tracer/propagation/lightstep_propagator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "tracer/propagation/propagator.h" 6 | 7 | #include 8 | 9 | namespace lightstep { 10 | extern const opentracing::string_view PrefixBaggage; 11 | 12 | std::unique_ptr MakeLightStepPropagator(); 13 | } // namespace lightstep 14 | -------------------------------------------------------------------------------- /ci/install_opentracing.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | [ -z "${OPENTRACING_VERSION}" ] && export OPENTRACING_VERSION="v1.5.0" 6 | 7 | # Build OpenTracing 8 | cd / 9 | git clone -b ${OPENTRACING_VERSION} https://github.com/opentracing/opentracing-cpp.git 10 | cd opentracing-cpp 11 | mkdir .build && cd .build 12 | cmake -DBUILD_TESTING=OFF .. 13 | make && make install 14 | -------------------------------------------------------------------------------- /lightstep-tracer-common/third_party/googleapis/README.lightstep-tracer-common: -------------------------------------------------------------------------------- 1 | Google APIs 2 | ============ 3 | 4 | Project: Google APIs 5 | URL: https://github.com/google/googleapis 6 | Revision: d6f78d948c53f3b400bb46996eb3084359914f9b 7 | License: Apache License 2.0 8 | 9 | 10 | Imported Files 11 | --------------- 12 | 13 | - google/api/annotations.proto 14 | - google/api/http.proto 15 | -------------------------------------------------------------------------------- /test/mock_satellite/mock_satellite.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package lightstep.mock_satellite; 4 | 5 | option go_package = "mocksatellitepb"; 6 | 7 | import "lightstep-tracer-common/collector.proto"; 8 | 9 | message Spans { 10 | repeated lightstep.collector.Span spans = 1; 11 | } 12 | 13 | message Reports { 14 | repeated lightstep.collector.ReportRequest reports = 1; 15 | } 16 | -------------------------------------------------------------------------------- /ci/run_lightstep_docker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | BUILD_IMAGE=lightstep-build 6 | docker image inspect "$BUILD_IMAGE" &> /dev/null || { 7 | docker build -t "$BUILD_IMAGE" ci 8 | } 9 | 10 | if [[ $# -ge 1 ]]; then 11 | docker run -v "$PWD":/src -w /src -it "$BUILD_IMAGE" "$@" 12 | else 13 | docker run -v "$PWD":/src -w /src --privileged -it "$BUILD_IMAGE" /bin/bash -l 14 | fi 15 | -------------------------------------------------------------------------------- /lightstep-tracer-configuration/BUILD: -------------------------------------------------------------------------------- 1 | proto_library( 2 | name = "tracer_configuration_proto", 3 | srcs = ["tracer_configuration.proto"], 4 | deps = [], 5 | visibility = ["//visibility:public"], 6 | ) 7 | 8 | cc_proto_library( 9 | name = "tracer_configuration_proto_cc", 10 | deps = [":tracer_configuration_proto"], 11 | visibility = ["//visibility:public"], 12 | ) 13 | 14 | -------------------------------------------------------------------------------- /lightstep-tracer-common/third_party/protobuf/README.lightstep-tracer-common: -------------------------------------------------------------------------------- 1 | protobuf 2 | ============ 3 | 4 | Project: protobuf 5 | URL: https://github.com/protocolbuffers/protobuf 6 | Revision: a03d332aca5d33c5d4b2cd25037c9e37d57eff02 7 | License: Google license 8 | 9 | 10 | Imported Files 11 | --------------- 12 | - src/google/protobuf/descriptor.proto 13 | - src/google/protobuf/timestamp.proto 14 | -------------------------------------------------------------------------------- /src/tracer/tag.cpp: -------------------------------------------------------------------------------- 1 | #include "tracer/tag.h" 2 | 3 | namespace lightstep { 4 | //-------------------------------------------------------------------------------------------------- 5 | // SamplingPriorityKey 6 | //-------------------------------------------------------------------------------------------------- 7 | const opentracing::string_view SamplingPriorityKey = "sampling.priority"; 8 | } // namespace lightstep 9 | -------------------------------------------------------------------------------- /benchmark/tracer_upload_bench/benchmark_report.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace lightstep { 7 | struct BenchmarkReport { 8 | std::chrono::microseconds duration; 9 | int num_spans_generated; 10 | int num_dropped_spans; 11 | int approx_span_size; 12 | }; 13 | 14 | std::ostream& operator<<(std::ostream& out, const BenchmarkReport& report); 15 | } // namespace lightstep 16 | -------------------------------------------------------------------------------- /src/recorder/no_grpc_transporter.cpp: -------------------------------------------------------------------------------- 1 | #include "recorder/grpc_transporter.h" 2 | 3 | #include 4 | 5 | namespace lightstep { 6 | std::unique_ptr MakeGrpcTransporter( 7 | Logger& /*logger*/, const LightStepTracerOptions& /*options*/) { 8 | throw std::runtime_error{ 9 | "LightStep was not built with gRPC support, so a transporter must be " 10 | "supplied."}; 11 | } 12 | } // namespace lightstep 13 | -------------------------------------------------------------------------------- /test/ports.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace lightstep { 6 | enum class PortAssignments : uint16_t { 7 | AresDnsResolverTest = 9000, 8 | SatelliteDnsResolutionManagerTest, 9 | SatelliteEndpointManagerTest, 10 | StreamRecorderTest, 11 | StreamRecorderForkTest, 12 | MockSatelliteTest, 13 | VectorWriteTestHttp, 14 | VectorWriteTestTcp, 15 | DynamicLoadTest 16 | }; 17 | } // namespace lightstep 18 | -------------------------------------------------------------------------------- /src/recorder/no_stream_recorder.cpp: -------------------------------------------------------------------------------- 1 | #include "recorder/stream_recorder.h" 2 | 3 | #include 4 | 5 | namespace lightstep { 6 | std::unique_ptr MakeStreamRecorder( 7 | Logger& /*logger*/, LightStepTracerOptions&& /*tracer_options*/) { 8 | throw std::runtime_error{ 9 | "LightStep was not built with stream recorder support, so a different " 10 | "recorder must be selected."}; 11 | } 12 | } // namespace lightstep 13 | -------------------------------------------------------------------------------- /3rd_party/base64/BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "//bazel:lightstep_build_system.bzl", 3 | "lightstep_cc_library", 4 | "lightstep_package", 5 | ) 6 | 7 | lightstep_package() 8 | 9 | exports_files(["LICENSE"]) 10 | 11 | lightstep_cc_library( 12 | name = "base64_lib", 13 | private_hdrs = [ 14 | "include/lightstep/base64/base64.h", 15 | ], 16 | srcs = [ 17 | "src/base64.cpp", 18 | ], 19 | is_3rd_party = True, 20 | ) 21 | -------------------------------------------------------------------------------- /bazel/glibc_version.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern "C" { 5 | __asm__(".symver memcpy,memcpy@GLIBC_2.2.5"); 6 | __asm__(".symver clock_gettime,clock_gettime@GLIBC_2.2.5"); 7 | 8 | void* __wrap_memcpy(void* dest, const void* src, size_t n) { 9 | return memcpy(dest, src, n); 10 | } 11 | 12 | int __wrap_clock_gettime(clockid_t clk_id, struct timespec* tp) { 13 | return clock_gettime(clk_id, tp); 14 | } 15 | } // extern "C" 16 | -------------------------------------------------------------------------------- /test/common/chunked_http_framing_test.cpp: -------------------------------------------------------------------------------- 1 | #include "common/chunked_http_framing.h" 2 | 3 | #include "3rd_party/catch2/catch.hpp" 4 | using namespace lightstep; 5 | 6 | TEST_CASE("ChunkedHttpFraming") { 7 | std::string header_serialization(ChunkedHttpMaxHeaderSize + 1, ' '); 8 | WriteHttpChunkHeader(&header_serialization[0], header_serialization.size(), 9 | 10); 10 | REQUIRE(header_serialization == " 0000000a\r\n"); 11 | } 12 | -------------------------------------------------------------------------------- /ci/install_clang.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | apt-get install --no-install-recommends --no-install-suggests -y \ 6 | gnupg2 \ 7 | software-properties-common \ 8 | wget 9 | 10 | wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - 11 | apt-add-repository "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-6.0 main" 12 | apt-get update 13 | apt-get install -y clang-6.0 clang-tidy 14 | -------------------------------------------------------------------------------- /src/common/platform/string.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace lightstep { 4 | /** 5 | * Portable wrapper to strcasecmp 6 | * See https://linux.die.net/man/3/strcasecmp 7 | */ 8 | int StrCaseCmp(const char* s1, const char* s2) noexcept; 9 | } // namespace lightstep 10 | 11 | #ifdef _WIN32 12 | #define WIN32_LEAN_AND_MEAN 13 | #define NOMINMAX 14 | #include 15 | #include 16 | #else 17 | #include 18 | #include 19 | #endif 20 | -------------------------------------------------------------------------------- /ci/setup_windows_build_environment.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = "Stop" 2 | trap { $host.SetShouldExit(1) } 3 | 4 | git clone -b 2020.01 https://github.com/Microsoft/vcpkg.git 5 | cd vcpkg 6 | $VCPKG_DIR=(Get-Item -Path ".\").FullName 7 | ./bootstrap-vcpkg.bat 8 | ./vcpkg integrate install 9 | ./vcpkg install libevent:x64-windows-static 10 | ./vcpkg install protobuf:x64-windows-static 11 | ./vcpkg install opentracing:x64-windows-static 12 | ./vcpkg install c-ares:x64-windows-static 13 | -------------------------------------------------------------------------------- /benchmark/tracer_upload_bench/tracer_upload_bench.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package lightstep.tracer_upload_bench; 4 | 5 | import "lightstep-tracer-configuration/tracer_configuration.proto"; 6 | 7 | message Configuration { 8 | lightstep.tracer_configuration.TracerConfiguration tracer_configuration = 1; 9 | int32 num_spans_per_thread = 2; 10 | int32 num_threads = 3; 11 | double spans_per_second = 4; 12 | int32 payload_size = 5; 13 | double startup_delay = 6; 14 | } 15 | -------------------------------------------------------------------------------- /test/mock_dns_server/mock_dns_server_handle.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "test/child_process_handle.h" 6 | 7 | namespace lightstep { 8 | /** 9 | * Manages a mock dns server started as a child process. 10 | */ 11 | class MockDnsServerHandle { 12 | public: 13 | MockDnsServerHandle() noexcept = default; 14 | 15 | explicit MockDnsServerHandle(uint16_t port); 16 | 17 | private: 18 | ChildProcessHandle handle_; 19 | }; 20 | } // namespace lightstep 21 | -------------------------------------------------------------------------------- /src/tracer/lightstep_tracer_factory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace lightstep { 8 | class LightStepTracerFactory final : public opentracing::TracerFactory { 9 | public: 10 | // opentracing::TracerFactory 11 | opentracing::expected> MakeTracer( 12 | const char* configuration, std::string& error_message) const 13 | noexcept override; 14 | }; 15 | } // namespace lightstep 16 | -------------------------------------------------------------------------------- /test/bridge/python/BUILD: -------------------------------------------------------------------------------- 1 | load("@python_pip_deps//:requirements.bzl", "requirement") 2 | load( 3 | "//bazel:lightstep_build_system.bzl", 4 | "lightstep_cc_library", 5 | "lightstep_package", 6 | ) 7 | 8 | lightstep_package() 9 | 10 | py_test( 11 | name = "tracer_test", 12 | srcs = [ 13 | "tracer_test.py", 14 | ], 15 | deps = [ 16 | requirement("opentracing"), 17 | ], 18 | data = [ 19 | "//bridge/python/binary/py3:lightstep_streaming.so", 20 | ], 21 | ) 22 | -------------------------------------------------------------------------------- /test/mock_dns_resolution_callback.cpp: -------------------------------------------------------------------------------- 1 | #include "test/mock_dns_resolution_callback.h" 2 | 3 | namespace lightstep { 4 | void MockDnsResolutionCallback::OnDnsResolution( 5 | const DnsResolution& resolution, 6 | opentracing::string_view error_message) noexcept { 7 | resolution.ForeachIpAddress([&](const IpAddress& ip_address) { 8 | ip_addresses_.push_back(ip_address); 9 | return true; 10 | }); 11 | error_message_ = error_message; 12 | event_base_.LoopBreak(); 13 | } 14 | } // namespace lightstep 15 | -------------------------------------------------------------------------------- /src/tracer/json_options.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace lightstep { 6 | /** 7 | * Construct LightStepTracerOptions from configuration json. 8 | * @param configuration the json configuration 9 | * @param error_message an error message provided upon failure 10 | * @return the LightStepTracerOptions or an error code 11 | */ 12 | opentracing::expected MakeTracerOptions( 13 | const char* configuration, std::string& error_message); 14 | } // namespace lightstep 15 | -------------------------------------------------------------------------------- /test/network/ares_dns_resolver/BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "//bazel:lightstep_build_system.bzl", 3 | "lightstep_catch_test", 4 | "lightstep_package", 5 | ) 6 | 7 | lightstep_package() 8 | 9 | lightstep_catch_test( 10 | name = "ares_dns_resolver_test", 11 | srcs = [ 12 | "ares_dns_resolver_test.cpp", 13 | ], 14 | deps = [ 15 | "//src/network/ares_dns_resolver:ares_dns_resolver_lib", 16 | "//test/mock_dns_server:mock_dns_server_lib", 17 | "//test:ports_lib", 18 | ], 19 | ) 20 | 21 | -------------------------------------------------------------------------------- /bazel/graphviz.BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_foreign_cc//tools/build_defs:configure.bzl", "configure_make") 2 | 3 | filegroup( 4 | name = "srcs", 5 | srcs = glob(["**"]), 6 | ) 7 | 8 | configure_make( 9 | name = "graphviz", 10 | lib_source = ":srcs", 11 | binaries = [ 12 | "dot", 13 | ], 14 | visibility = ["//visibility:public"], 15 | ) 16 | 17 | filegroup( 18 | name = "dot_filegroup", 19 | srcs = [":graphviz"], 20 | output_group = "dot", 21 | visibility = ["//visibility:public"], 22 | ) 23 | 24 | -------------------------------------------------------------------------------- /ci/install_grpc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | [ -z "${GRPC_VERSION}" ] && export GRPC_VERSION="v1.10.0" 6 | 7 | apt-get update 8 | apt-get install --no-install-recommends --no-install-suggests -y \ 9 | golang 10 | 11 | 12 | 13 | ### Build gRPC 14 | cd / 15 | git clone -b ${GRPC_VERSION} https://github.com/grpc/grpc 16 | cd grpc 17 | git submodule update --init 18 | make HAS_SYSTEM_PROTOBUF=false && make install 19 | make && make install 20 | cd third_party/protobuf 21 | make install 22 | ldconfig 23 | -------------------------------------------------------------------------------- /src/common/platform/network_environment.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace lightstep { 4 | /** 5 | * Manages the initialization and deinitialization of the process's network 6 | * environment. On unix systems, this does nothing; on windows, it calls 7 | * WSAStartup and WSACleanup. 8 | * 9 | * See 10 | * https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-wsastartup 11 | */ 12 | class NetworkEnvironment { 13 | public: 14 | NetworkEnvironment(); 15 | 16 | ~NetworkEnvironment() noexcept; 17 | }; 18 | } // namespace lightstep 19 | -------------------------------------------------------------------------------- /ci/install_bazel.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | [ -z "${BAZEL_VERSION}" ] && export BAZEL_VERSION="2.0.0" 6 | 7 | apt-get update 8 | apt-get install --no-install-recommends --no-install-suggests -y \ 9 | wget \ 10 | unzip \ 11 | ca-certificates \ 12 | openjdk-8-jdk 13 | wget https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VERSION}/bazel-${BAZEL_VERSION}-installer-linux-x86_64.sh 14 | chmod +x bazel-${BAZEL_VERSION}-installer-linux-x86_64.sh 15 | ./bazel-${BAZEL_VERSION}-installer-linux-x86_64.sh 16 | -------------------------------------------------------------------------------- /src/recorder/stream_recorder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/logger.h" 4 | #include "lightstep/tracer.h" 5 | #include "recorder/recorder.h" 6 | 7 | namespace lightstep { 8 | /** 9 | * Constructs a StreamRecorder. 10 | * @param logger supplies the place to write logs. 11 | * @params tracer_options supplies the user-provided configuration options to 12 | * apply. 13 | * @return a StreamRecorder 14 | */ 15 | std::unique_ptr MakeStreamRecorder( 16 | Logger& logger, LightStepTracerOptions&& tracer_options); 17 | } // namespace lightstep 18 | -------------------------------------------------------------------------------- /ci/install_protobuf.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | [ -z "${PROTOBUF_VERSION}" ] && export PROTOBUF_VERSION="3.5.1" 6 | 7 | apt-get update 8 | apt-get install --no-install-recommends --no-install-suggests -y \ 9 | curl 10 | 11 | # Make sure you grab the latest version 12 | cd / 13 | curl -OL https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protobuf-cpp-${PROTOBUF_VERSION}.tar.gz 14 | tar zxf protobuf-cpp-${PROTOBUF_VERSION}.tar.gz 15 | cd protobuf-${PROTOBUF_VERSION} 16 | ./configure 17 | make && make install 18 | ldconfig 19 | -------------------------------------------------------------------------------- /src/recorder/grpc_transporter/BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "//bazel:lightstep_build_system.bzl", 3 | "lightstep_cc_library", 4 | "lightstep_package", 5 | ) 6 | 7 | lightstep_package() 8 | 9 | lightstep_cc_library( 10 | name = "grpc_transporter_lib", 11 | srcs = [ 12 | "grpc_transporter.cpp", 13 | ], 14 | deps = [ 15 | "//src/recorder:grpc_transporter_interface", 16 | "//src/common:logger_lib", 17 | "//include/lightstep:tracer_interface", 18 | "//lightstep-tracer-common:collector_proto_grpc", 19 | ], 20 | ) 21 | -------------------------------------------------------------------------------- /src/recorder/transporter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "lightstep-tracer-common/collector.pb.h" 3 | 4 | namespace lightstep { 5 | //------------------------------------------------------------------------------ 6 | // MakeCollectorResponse 7 | //------------------------------------------------------------------------------ 8 | std::unique_ptr 9 | Transporter::MakeCollectorResponse() { 10 | return std::unique_ptr{ 11 | new collector::ReportResponse{}}; 12 | } 13 | } // namespace lightstep 14 | -------------------------------------------------------------------------------- /3rd_party/catch2/BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "//bazel:lightstep_build_system.bzl", 3 | "lightstep_cc_library", 4 | "lightstep_package", 5 | ) 6 | 7 | lightstep_package() 8 | 9 | # From commit a575536abe20b58c48863600f8a71e93b4052b81 10 | lightstep_cc_library( 11 | name = "catch2", 12 | hdrs = [ 13 | "catch.hpp", 14 | ], 15 | is_3rd_party = True, 16 | ) 17 | 18 | lightstep_cc_library( 19 | name = "main_lib", 20 | srcs = [ 21 | "catch_main.cpp", 22 | ], 23 | deps = [ 24 | ":catch2", 25 | ], 26 | is_3rd_party = True, 27 | ) 28 | -------------------------------------------------------------------------------- /src/common/in_memory_stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace lightstep { 7 | // Classes to allow construction of an istream from constant memory without 8 | // copying. See https://stackoverflow.com/a/13059195/4447365. 9 | class in_memory_buffer : public std::streambuf { 10 | public: 11 | in_memory_buffer(const char* data, size_t size); 12 | }; 13 | 14 | class in_memory_stream : virtual public in_memory_buffer, public std::istream { 15 | public: 16 | in_memory_stream(const char* data, size_t size); 17 | }; 18 | } // namespace lightstep 19 | -------------------------------------------------------------------------------- /bridge/python/wheel/generate_record.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import base64 3 | import sys 4 | import os 5 | 6 | root = sys.argv[1] 7 | 8 | for subdir, _, files in os.walk(root): 9 | for filename in files: 10 | path = os.path.join(subdir, filename) 11 | relative_path = path[len(root)+1:] 12 | with open(path, 'r') as f: 13 | data = f.read() 14 | num_bytes = len(data) 15 | sha256 = hashlib.sha256(data).digest() 16 | sha256 = base64.urlsafe_b64encode(sha256).rstrip('=') 17 | print "%s,%s,%d" % (relative_path, sha256, num_bytes) 18 | -------------------------------------------------------------------------------- /test/cmake/load_tracer_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | int main(int argc, char* argv[]) { 6 | if (argc != 2) { 7 | std::cerr << "Usage: \n"; 8 | return -1; 9 | } 10 | 11 | // Verify we can load the tracer library. 12 | std::string error_message; 13 | auto handle_maybe = 14 | opentracing::DynamicallyLoadTracingLibrary(argv[1], error_message); 15 | if (!handle_maybe) { 16 | std::cerr << "Failed to load tracer library " << error_message << "\n"; 17 | return -1; 18 | } 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /bazel/cares.BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_foreign_cc//tools/build_defs:cmake.bzl", "cmake_external") 2 | 3 | 4 | filegroup( 5 | name = "srcs", 6 | srcs = glob(["**"]), 7 | ) 8 | 9 | cmake_external( 10 | name = "ares", 11 | cache_entries = { 12 | "CMAKE_BUILD_TYPE": "Release", 13 | "CARES_SHARED": "off", 14 | "CARES_STATIC": "on", 15 | "CARES_STATIC_PIC": "on", 16 | "CARES_BUILD_TESTS": "off", 17 | "CARES_BUILD_TOOLS": "off", 18 | }, 19 | lib_source = ":srcs", 20 | static_libraries = ["libcares.a"], 21 | visibility = ["//visibility:public"], 22 | ) 23 | 24 | -------------------------------------------------------------------------------- /src/recorder/serialization/report_request_header.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "lightstep/tracer.h" 7 | 8 | namespace lightstep { 9 | /** 10 | * Serializes the common parts of a ReportRequest. 11 | * @param tracer_options the options used to construct the tracer. 12 | * @param reporter_id a unique ID for the reporter. 13 | * @return a string with the common parts of the ReportRequest serialization. 14 | */ 15 | std::string WriteReportRequestHeader( 16 | const LightStepTracerOptions& tracer_options, uint64_t reporter_id); 17 | } // namespace lightstep 18 | -------------------------------------------------------------------------------- /test/echo_server/echo_server_handle.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "test/child_process_handle.h" 6 | #include "test/http_connection.h" 7 | 8 | namespace lightstep { 9 | /** 10 | * Manages a server that stores and returns any data sent. 11 | */ 12 | class EchoServerHandle { 13 | public: 14 | EchoServerHandle(uint16_t http_port, uint16_t tcp_port); 15 | 16 | /** 17 | * @return the data sent to the server. 18 | */ 19 | std::string data(); 20 | 21 | private: 22 | ChildProcessHandle handle_; 23 | HttpConnection http_connection_; 24 | }; 25 | } // namespace lightstep 26 | -------------------------------------------------------------------------------- /test/tracer/utility_test.cpp: -------------------------------------------------------------------------------- 1 | #include "tracer/utility.h" 2 | 3 | #include "3rd_party/catch2/catch.hpp" 4 | using namespace lightstep; 5 | 6 | TEST_CASE("We can append the values of w3 trace-state values") { 7 | std::string trace_state; 8 | 9 | SECTION("We can append to an empty trace-state") { 10 | AppendTraceState(trace_state, "abc=123"); 11 | REQUIRE(trace_state == "abc=123"); 12 | } 13 | 14 | SECTION("We can append to a non-empty trace-state") { 15 | trace_state = "abc=123"; 16 | AppendTraceState(trace_state, "xyz=456"); 17 | REQUIRE(trace_state == "abc=123,xyz=456"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /bazel/valgrind.BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_foreign_cc//tools/build_defs:configure.bzl", "configure_make") 2 | 3 | filegroup( 4 | name = "srcs", 5 | srcs = glob(["**"]), 6 | ) 7 | 8 | configure_make( 9 | name = "valgrind", 10 | configure_options = [ 11 | "CFLAGS='-fno-stack-protector'", 12 | ], 13 | lib_source = ":srcs", 14 | binaries = [ 15 | "valgrind", 16 | ], 17 | visibility = ["//visibility:public"], 18 | ) 19 | 20 | filegroup( 21 | name = "valgrind_filegroup", 22 | srcs = [":valgrind"], 23 | output_group = "valgrind", 24 | visibility = ["//visibility:public"], 25 | ) 26 | -------------------------------------------------------------------------------- /src/recorder/stream_recorder/utility.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace lightstep { 9 | /** 10 | * Separates a vector of host-port pairs into a bector of unique hosts and 11 | * indexed endpoints. 12 | * @param endpoints a vector of host-port pairs. 13 | * @return a vector of unique hosts and a vector of indexed endpoints. 14 | */ 15 | std::pair, std::vector>> 16 | SeparateEndpoints( 17 | const std::vector>& endpoints); 18 | } // namespace lightstep 19 | -------------------------------------------------------------------------------- /test/common/random_test.cpp: -------------------------------------------------------------------------------- 1 | #include "common/random.h" 2 | 3 | #include "3rd_party/catch2/catch.hpp" 4 | using namespace lightstep; 5 | 6 | TEST_CASE("Random") { 7 | SECTION("GenerateId returns a random 64-bit number.") { 8 | auto x = GenerateId(); 9 | auto y = GenerateId(); 10 | REQUIRE(x != y); 11 | } 12 | 13 | SECTION( 14 | "GeneateRandomDuration returns a random duration within a given range.") { 15 | auto a = std::chrono::microseconds{5}; 16 | auto b = std::chrono::microseconds{10}; 17 | auto t = GenerateRandomDuration(a, b); 18 | REQUIRE(a <= t); 19 | REQUIRE(t <= b); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /3rd_party/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(LIGHTSTEP_THIRD_PARTY_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/catch2/include 2 | ${CMAKE_CURRENT_SOURCE_DIR}/base64/include 3 | ) 4 | set(LIGHTSTEP_THIRD_PARTY_INCLUDES ${LIGHTSTEP_THIRD_PARTY_INCLUDES} 5 | PARENT_SCOPE) 6 | 7 | include_directories(SYSTEM ${LIGHTSTEP_THIRD_PARTY_INCLUDES}) 8 | add_library(lightstep_3rd_party OBJECT base64/src/base64.cpp) 9 | 10 | if (BUILD_SHARED_LIBS) 11 | set_property(TARGET lightstep_3rd_party PROPERTY POSITION_INDEPENDENT_CODE ON) 12 | endif() 13 | 14 | add_executable(embedfile embedfile/src/embedfile.c) 15 | -------------------------------------------------------------------------------- /src/tracer/baggage_flat_map.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "common/flat_map.h" 7 | 8 | #include 9 | 10 | namespace lightstep { 11 | struct StringViewComparison { 12 | bool operator()(opentracing::string_view lhs, 13 | opentracing::string_view rhs) const noexcept { 14 | return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), 15 | rhs.end()); 16 | } 17 | }; 18 | 19 | using BaggageFlatMap = FlatMap; 20 | } // namespace lightstep 21 | -------------------------------------------------------------------------------- /test/recorder/stream_recorder/host_header_test.cpp: -------------------------------------------------------------------------------- 1 | #include "recorder/stream_recorder/host_header.h" 2 | 3 | #include "3rd_party/catch2/catch.hpp" 4 | using namespace lightstep; 5 | 6 | TEST_CASE("HostHeader") { 7 | LightStepTracerOptions options; 8 | options.satellite_endpoints = {{"abc", 123}, {"abc123", 456}}; 9 | HostHeader host_header{options}; 10 | const char* header = static_cast(host_header.fragment().first); 11 | 12 | host_header.set_host("abc"); 13 | REQUIRE(std::string{header} == "Host: abc\r\n"); 14 | 15 | host_header.set_host("abc123"); 16 | REQUIRE(std::string{header} == "Host:abc123\r\n"); 17 | } 18 | -------------------------------------------------------------------------------- /test/bridge/python/span_probe.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import lightstep_streaming 3 | 4 | if len(sys.argv) != 3: 5 | print("Usage: span_probe.py ") 6 | sys.exit(-1) 7 | 8 | 9 | host = sys.argv[1] 10 | port = sys.argv[2] 11 | 12 | tracer = lightstep_streaming.Tracer( 13 | component_name = "span_probe", 14 | access_token = "abc", 15 | collector_plaintext = True, 16 | use_stream_recorder = True, 17 | satellite_endpoints = [{ 18 | 'host': host, 19 | 'port': int(port) 20 | }] 21 | ) 22 | 23 | span = tracer.start_span('A') 24 | span.finish() 25 | 26 | tracer.close() 27 | -------------------------------------------------------------------------------- /src/network/vector_write.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "common/fragment_input_stream.h" 6 | 7 | namespace lightstep { 8 | /** 9 | * Uses the writev system call to send fragments over a given socket. After 10 | * writing, consumes the number of written bytes from the streams. 11 | * @param socket the file descriptor of the socket. 12 | * @param fragment_input_streams the list of fragments to send. 13 | * @return true if everything in the streams was written; false, otherwise. 14 | */ 15 | bool Write(int socket, 16 | std::initializer_list fragment_input_streams); 17 | } // namespace lightstep 18 | -------------------------------------------------------------------------------- /benchmark/tracer_upload_bench/span_drop_counter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "lightstep/metrics_observer.h" 6 | 7 | namespace lightstep { 8 | /** 9 | * Recorder for dropped spans 10 | */ 11 | class SpanDropCounter : public MetricsObserver { 12 | public: 13 | /** 14 | * @return the number of dropped spans recorded 15 | */ 16 | int num_dropped_spans() const noexcept { return num_dropped_spans_; } 17 | 18 | // MetricsObserver 19 | void OnSpansDropped(int num_spans) noexcept override { 20 | num_dropped_spans_ += num_spans; 21 | } 22 | 23 | private: 24 | std::atomic num_dropped_spans_{0}; 25 | }; 26 | } // namespace lightstep 27 | -------------------------------------------------------------------------------- /bazel/libevent.BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_foreign_cc//tools/build_defs:cmake.bzl", "cmake_external") 2 | 3 | 4 | filegroup( 5 | name = "srcs", 6 | srcs = glob(["**"]), 7 | ) 8 | 9 | cmake_external( 10 | name = "libevent", 11 | cache_entries = { 12 | "CMAKE_BUILD_TYPE": "Release", 13 | "CMAKE_POSITION_INDEPENDENT_CODE" : "on", 14 | "BUILD_SHARED_LIBS": "off", 15 | "BUILD_STATIC_LIBS": "on", 16 | "EVENT__DISABLE_OPENSSL": "on", 17 | "EVENT__DISABLE_REGRESS": "on", 18 | "EVENT__DISABLE_TESTS": "on", 19 | }, 20 | lib_source = ":srcs", 21 | static_libraries = ["libevent.a"], 22 | visibility = ["//visibility:public"], 23 | ) 24 | -------------------------------------------------------------------------------- /src/tracer/counting_metrics_observer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "lightstep/metrics_observer.h" 6 | 7 | namespace lightstep { 8 | struct CountingMetricsObserver : MetricsObserver { 9 | // MetricsObserver 10 | void OnSpansSent(int num_spans) noexcept override { 11 | num_spans_sent += num_spans; 12 | } 13 | 14 | void OnSpansDropped(int num_spans) noexcept override { 15 | num_spans_dropped += num_spans; 16 | } 17 | 18 | void OnFlush() noexcept override { ++num_flushes; } 19 | 20 | std::atomic num_flushes{0}; 21 | std::atomic num_spans_sent{0}; 22 | std::atomic num_spans_dropped{0}; 23 | }; 24 | } // namespace lightstep 25 | -------------------------------------------------------------------------------- /src/common/noncopyable.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace lightstep { 4 | /** 5 | * Helper class to ensure a class doesn't define unwanted copy methods. 6 | * 7 | * Modeled after boost::noncopyable 8 | * See 9 | * https://www.boost.org/doc/libs/1_68_0/libs/core/doc/html/core/noncopyable.html 10 | */ 11 | class Noncopyable { 12 | public: 13 | Noncopyable(const Noncopyable&) = delete; 14 | Noncopyable(Noncopyable&&) = delete; 15 | 16 | ~Noncopyable() noexcept = default; 17 | 18 | Noncopyable& operator=(const Noncopyable&) = delete; 19 | Noncopyable& operator=(Noncopyable&&) = delete; 20 | 21 | protected: 22 | Noncopyable() noexcept = default; 23 | }; 24 | } // namespace lightstep 25 | -------------------------------------------------------------------------------- /src/common/platform/utility_unix.cpp: -------------------------------------------------------------------------------- 1 | #include "common/platform/utility.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | namespace lightstep { 9 | std::string GetProgramName() { 10 | constexpr int path_max = 1024; 11 | std::unique_ptr exe_path{new char[path_max]}; 12 | ssize_t size = ::readlink("/proc/self/exe", exe_path.get(), path_max); 13 | if (size == -1) { 14 | return "c++-program"; // Dunno... 15 | } 16 | std::string path(exe_path.get(), size); 17 | size_t lslash = path.rfind('/'); 18 | if (lslash != std::string::npos) { 19 | return path.substr(lslash + 1); 20 | } 21 | return path; 22 | } 23 | } // namespace lightstep 24 | -------------------------------------------------------------------------------- /src/common/spin_lock_mutex.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace lightstep { 7 | /** 8 | * Simple spin lock implementation. 9 | * 10 | * See https://stackoverflow.com/a/29195378/4447365 11 | */ 12 | class SpinLockMutex { 13 | public: 14 | // std Mutex requirements 15 | inline void lock() noexcept { 16 | while (locked_.test_and_set(std::memory_order_acquire)) { 17 | } 18 | } 19 | 20 | inline void unlock() noexcept { locked_.clear(std::memory_order_release); } 21 | 22 | private: 23 | std::atomic_flag locked_ = ATOMIC_FLAG_INIT; 24 | }; 25 | 26 | using SpinLockGuard = std::lock_guard; 27 | } // namespace lightstep 28 | -------------------------------------------------------------------------------- /test/recorder/stream_recorder/fragment_span_input_stream_test.cpp: -------------------------------------------------------------------------------- 1 | #include "recorder/stream_recorder/fragment_span_input_stream.h" 2 | 3 | #include 4 | 5 | #include "3rd_party/catch2/catch.hpp" 6 | #include "test/utility.h" 7 | using namespace lightstep; 8 | 9 | TEST_CASE("FragmentSpanInputStream") { 10 | FragmentSpanInputStream stream; 11 | const char* s1 = "abc"; 12 | const char* s2 = "123"; 13 | 14 | REQUIRE(stream.empty()); 15 | REQUIRE(stream.chunk_start() == nullptr); 16 | 17 | SECTION("Set adds fragments for a span.") { 18 | CircularBufferConstPlacement placement{s1, 2, s2, 3}; 19 | stream.Set(placement, s1 + 1); 20 | REQUIRE(ToString(stream) == "b123"); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/recorder/stream_recorder/status_line_parser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace lightstep { 8 | class StatusLineParser { 9 | public: 10 | void Reset() noexcept; 11 | 12 | void Parse(opentracing::string_view s); 13 | 14 | bool completed() const noexcept { return complete_; } 15 | 16 | int status_code() const noexcept { return status_code_; } 17 | 18 | opentracing::string_view reason() const noexcept { return reason_; } 19 | 20 | private: 21 | std::string line_; 22 | bool complete_{false}; 23 | int status_code_; 24 | opentracing::string_view reason_; 25 | 26 | void ParseFields(); 27 | }; 28 | } // namespace lightstep 29 | -------------------------------------------------------------------------------- /lightstep-tracer-common/lightstep_carrier.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package lightstep; 4 | 5 | option go_package = "lightsteppb"; 6 | 7 | // The standard carrier for binary context propagation into LightStep. 8 | message BinaryCarrier { 9 | // "text_ctx" was deprecated following lightstep-tracer-cpp-0.36 10 | repeated bytes deprecated_text_ctx = 1; 11 | 12 | // The Opentracing "basictracer" proto. 13 | BasicTracerCarrier basic_ctx = 2; 14 | } 15 | 16 | // Copy of https://github.com/opentracing/basictracer-go/blob/master/wire/wire.proto 17 | message BasicTracerCarrier { 18 | fixed64 trace_id = 1; 19 | fixed64 span_id = 2; 20 | bool sampled = 3; 21 | map baggage_items = 4; 22 | } 23 | -------------------------------------------------------------------------------- /src/common/random_traverser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "common/function_ref.h" 6 | 7 | namespace lightstep { 8 | /** 9 | * Iterate over indexes in random order. 10 | */ 11 | class RandomTraverser { 12 | public: 13 | using Callback = FunctionRef; 14 | 15 | explicit RandomTraverser(int n); 16 | 17 | /** 18 | * Iterates over over indexes in random order. 19 | * @param callback the callback to call with each index. Callback can return 20 | * false to exit early. 21 | * @return false if callback exited early; otherwise, true. 22 | */ 23 | bool ForEachIndex(Callback callback); 24 | 25 | private: 26 | std::vector indexes_; 27 | }; 28 | } // namespace lightstep 29 | -------------------------------------------------------------------------------- /src/network/ares_dns_resolver/BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "//bazel:lightstep_build_system.bzl", 3 | "lightstep_cc_library", 4 | "lightstep_package", 5 | ) 6 | 7 | lightstep_package() 8 | 9 | lightstep_cc_library( 10 | name = "ares_dns_resolver_lib", 11 | srcs = [ 12 | "ares_dns_resolver.h", 13 | "ares_dns_resolver.cpp", 14 | "ares_library_handle.h", 15 | "ares_library_handle.cpp", 16 | ], 17 | deps = [ 18 | "//src/common:noncopyable_lib", 19 | "//src/network:dns_resolver_interface", 20 | "//src/network:event_lib", 21 | "//src/network:timer_event_lib", 22 | ], 23 | external_deps = [ 24 | "@com_github_cares_cares//:ares", 25 | ], 26 | ) 27 | -------------------------------------------------------------------------------- /src/network/ares_dns_resolver/ares_library_handle.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "common/noncopyable.h" 6 | 7 | namespace lightstep { 8 | /** 9 | * Manages initialization of the c-ares library. 10 | */ 11 | class AresLibraryHandle : private Noncopyable { 12 | public: 13 | ~AresLibraryHandle() noexcept; 14 | 15 | // We use a global variable to initialize the ares library because 16 | // ares_library_init is not thread-safe and must be called before other 17 | // threads are started. 18 | // 19 | // See https://c-ares.haxx.se/ares_library_init.html 20 | static std::shared_ptr Instance; 21 | 22 | private: 23 | AresLibraryHandle(); 24 | }; 25 | } // namespace lightstep 26 | -------------------------------------------------------------------------------- /test/common/fast_random_number_generator_test.cpp: -------------------------------------------------------------------------------- 1 | #include "common/fast_random_number_generator.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "3rd_party/catch2/catch.hpp" 7 | using namespace lightstep; 8 | 9 | TEST_CASE("FastRandomNumberGenerator") { 10 | std::seed_seq seed_sequence{1, 2, 3}; 11 | FastRandomNumberGenerator random_number_generator; 12 | random_number_generator.seed(seed_sequence); 13 | 14 | SECTION( 15 | "If seededed, we can expect FastRandomNumberGenerator to have a long " 16 | "period before it repeats itself") { 17 | std::set values; 18 | for (int i = 0; i < 1000; ++i) { 19 | REQUIRE(values.insert(random_number_generator()).second); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/common/chunked_http_framing.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/hex_conversion.h" 4 | 5 | #include 6 | 7 | namespace lightstep { 8 | const size_t ChunkedHttpMaxHeaderSize = Num32BitHexDigits + 2; 9 | 10 | const opentracing::string_view ChunkedHttpFooter = "\r\n"; 11 | 12 | /** 13 | * Write the header part of framing for an http/1.1 chunk. 14 | * @param data start of the buffer to write to. 15 | * @param size the size of the buffer 16 | * @param chunk_size the size of the chunk. 17 | * 18 | * Note: Data is written from the end of the provided buffer. 19 | */ 20 | size_t WriteHttpChunkHeader(char* data, size_t size, 21 | uint32_t chunk_size) noexcept; 22 | } // namespace lightstep 23 | -------------------------------------------------------------------------------- /test/string_logger_sink.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace lightstep { 8 | /** 9 | * A log sink that concatenates all records into a string. 10 | */ 11 | class StringLoggerSink { 12 | public: 13 | /** 14 | * Append the given log. 15 | * @param log_level the level to log at 16 | * @param message the log message 17 | */ 18 | void operator()(LogLevel log_level, 19 | opentracing::string_view message) noexcept; 20 | 21 | /** 22 | * @return a string of concatenated log records. 23 | */ 24 | std::string contents(); 25 | 26 | private: 27 | std::mutex mutex_; 28 | std::ostringstream oss_; 29 | }; 30 | } // namespace lightstep 31 | -------------------------------------------------------------------------------- /src/tracer/utility.cpp: -------------------------------------------------------------------------------- 1 | #include "tracer/utility.h" 2 | 3 | namespace lightstep { 4 | //-------------------------------------------------------------------------------------------------- 5 | // AppendTraceState 6 | //-------------------------------------------------------------------------------------------------- 7 | void AppendTraceState(std::string& trace_state, 8 | opentracing::string_view key_values) { 9 | if (trace_state.empty()) { 10 | trace_state.assign(key_values.data(), key_values.size()); 11 | return; 12 | } 13 | trace_state.reserve(trace_state.size() + 1 + key_values.size()); 14 | trace_state.append(","); 15 | trace_state.append(key_values.data(), key_values.size()); 16 | } 17 | } // namespace lightstep 18 | -------------------------------------------------------------------------------- /test/echo_server/BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "//bazel:lightstep_build_system.bzl", 3 | "lightstep_package", 4 | "lightstep_cc_library", 5 | "lightstep_go_binary", 6 | ) 7 | 8 | lightstep_package() 9 | 10 | lightstep_go_binary( 11 | name = "echo_server", 12 | srcs = [ 13 | "main.go", 14 | ], 15 | out = "echo_server", 16 | ) 17 | 18 | lightstep_cc_library( 19 | name = "echo_server_lib", 20 | private_hdrs = [ 21 | "echo_server_handle.h", 22 | ], 23 | srcs = [ 24 | "echo_server_handle.cpp", 25 | ], 26 | deps = [ 27 | "//test:child_process_handle_lib", 28 | "//test:utility_lib", 29 | "//test:http_connection_lib", 30 | ], 31 | data = [ 32 | ":echo_server", 33 | ], 34 | ) 35 | -------------------------------------------------------------------------------- /src/common/platform/utility_windows.cpp: -------------------------------------------------------------------------------- 1 | #include "common/platform/utility.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | namespace lightstep { 9 | std::string GetProgramName() { 10 | const int path_max = 1024; 11 | TCHAR exe_path_char[path_max]; 12 | 13 | // this returns a DWORD by default 14 | auto size = 15 | static_cast(GetModuleFileName(nullptr, exe_path_char, path_max)); 16 | 17 | std::string exe_path{exe_path_char}; 18 | 19 | if (size <= 0) { 20 | return "c++-program"; // Dunno... 21 | } 22 | 23 | size_t lslash = exe_path.rfind('\\'); 24 | if (lslash != std::string::npos) { 25 | return exe_path.substr(lslash + 1); 26 | } 27 | return exe_path; 28 | } 29 | } // namespace lightstep 30 | -------------------------------------------------------------------------------- /test/recorder/in_memory_recorder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "recorder/recorder.h" 4 | 5 | #include 6 | #include 7 | 8 | namespace lightstep { 9 | // InMemoryRecorder is used for testing only. 10 | class InMemoryRecorder final : public Recorder { 11 | public: 12 | std::vector spans() const; 13 | 14 | size_t size() const; 15 | 16 | collector::Span top() const; 17 | 18 | // Recorder 19 | void RecordSpan(const collector::Span& span) noexcept override; 20 | 21 | void RecordSpan(Fragment header_fragment, 22 | std::unique_ptr&& span) noexcept override; 23 | 24 | private: 25 | mutable std::mutex mutex_; 26 | std::vector spans_; 27 | }; 28 | } // namespace lightstep 29 | -------------------------------------------------------------------------------- /src/tracer/propagation/propagation_options.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "tracer/propagation/propagator.h" 7 | 8 | #include 9 | 10 | namespace lightstep { 11 | struct PropagationOptions { 12 | std::vector> inject_propagators; 13 | std::vector> extract_propagators; 14 | }; 15 | 16 | void SetInjectExtractPropagationModes( 17 | const std::vector& propagation_modes, 18 | std::vector& inject_propagation_modes, 19 | std::vector& extract_propagation_modes); 20 | 21 | PropagationOptions MakePropagationOptions( 22 | const LightStepTracerOptions& options); 23 | } // namespace lightstep 24 | -------------------------------------------------------------------------------- /ci/install_cmake.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = "Stop" 2 | trap { $host.SetShouldExit(1) } 3 | 4 | $CMAKE_VERSION="3.15.2" 5 | $CWD=(Get-Item -Path ".\").FullName 6 | (new-object System.Net.WebClient). ` 7 | DownloadFile("https://github.com/Kitware/CMake/releases/download/v$CMAKE_VERSION/cmake-$CMAKE_VERSION-win64-x64.zip", ` 8 | "$CWD\cmake-$CMAKE_VERSION-win64-x64.zip") 9 | 10 | unzip cmake-$CMAKE_VERSION-win64-x64.zip 11 | 12 | $ENV:PATH="$ENV:PATH;$CWD\cmake-$CMAKE_VERSION-win64-x64\bin" 13 | cmake --help 14 | [Environment]::SetEnvironmentVariable( 15 | "Path", 16 | [Environment]::GetEnvironmentVariable("Path", [EnvironmentVariableTarget]::Machine) + ";$CWD\cmake-$CMAKE_VERSION-win64-x64\bin", 17 | [EnvironmentVariableTarget]::Machine) 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.lo 3 | *~ 4 | *.dSYM 5 | Makefile.in 6 | aclocal.m4 7 | autom4te.cache 8 | compile 9 | config.guess 10 | config.sub 11 | configure 12 | depcomp 13 | install-sh 14 | ltmain.sh 15 | missing 16 | Makefile.in 17 | .deps 18 | .libs 19 | lt*.m4 20 | libtool.m4 21 | Makefile 22 | config.log 23 | config.status 24 | libtool 25 | Makefile 26 | config.h 27 | *.la 28 | .dirstamp 29 | stamp-h1 30 | tracer_test 31 | carrier_test 32 | cppclient 33 | flushproto_test 34 | *.pb.h 35 | *.pb.cc 36 | *.stamp 37 | test-driver 38 | *.log 39 | *.trs 40 | linux 41 | *.gch 42 | 43 | # Ignore all bazel-* symlinks. There is no full list since this can change 44 | # based on the name of the directory bazel is cloned into.bazel-* 45 | /bazel-* 46 | 47 | # compilation database 48 | compile_commands.json 49 | -------------------------------------------------------------------------------- /test/common/function_ref_test.cpp: -------------------------------------------------------------------------------- 1 | #include "common/function_ref.h" 2 | 3 | #include "3rd_party/catch2/catch.hpp" 4 | using namespace lightstep; 5 | 6 | int Call(FunctionRef f) { return f(); } 7 | 8 | int Return3() { return 3; } 9 | 10 | TEST_CASE("FunctionRef") { 11 | int x = 9; 12 | 13 | auto f = [&] { return x; }; 14 | 15 | SECTION("FunctionRef can reference a lambda functor.") { 16 | REQUIRE(Call(f) == 9); 17 | } 18 | 19 | SECTION("FunctionRef can reference a function pointer.") { 20 | REQUIRE(Call(Return3) == 3); 21 | } 22 | 23 | SECTION("FunctionRef can be converted to bool") { 24 | FunctionRef fref1{nullptr}; 25 | FunctionRef fref2{f}; 26 | REQUIRE(!static_cast(fref1)); 27 | REQUIRE(static_cast(fref2)); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /3rd_party/catch2/catch_main.cpp: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_RUNNER 2 | #include "catch.hpp" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | // Taken from https://stackoverflow.com/a/77336/4447365 11 | void handler(int sig) { 12 | void *array[100]; 13 | size_t size; 14 | 15 | // get void*'s for all entries on the stack 16 | size = backtrace(array, 100); 17 | 18 | // print out all the frames to stderr 19 | fprintf(stderr, "Error: signal %d:\n", sig); 20 | backtrace_symbols_fd(array, size, STDERR_FILENO); 21 | exit(1); 22 | } 23 | 24 | int main( int argc, char* argv[] ) { 25 | signal(SIGSEGV, handler); 26 | signal(SIGTERM, handler); 27 | 28 | int result = Catch::Session().run( argc, argv ); 29 | 30 | return result; 31 | } 32 | -------------------------------------------------------------------------------- /src/common/platform/network_environment_unix.cpp: -------------------------------------------------------------------------------- 1 | #include "common/platform/network_environment.h" 2 | 3 | namespace lightstep { 4 | //-------------------------------------------------------------------------------------------------- 5 | // constructor 6 | //-------------------------------------------------------------------------------------------------- 7 | NetworkEnvironment::NetworkEnvironment() { 8 | (void)1; // silence clang-tidy warning 9 | } 10 | 11 | //-------------------------------------------------------------------------------------------------- 12 | // destructor 13 | //-------------------------------------------------------------------------------------------------- 14 | NetworkEnvironment::~NetworkEnvironment() noexcept { 15 | (void)1; // silence clang-tidy warning 16 | } 17 | } // namespace lightstep 18 | -------------------------------------------------------------------------------- /test/child_process_handle.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace lightstep { 7 | /** 8 | * Manages a child process. 9 | */ 10 | class ChildProcessHandle { 11 | public: 12 | ChildProcessHandle() noexcept = default; 13 | 14 | ChildProcessHandle(const char* command, 15 | const std::vector& arguments); 16 | 17 | ChildProcessHandle(const ChildProcessHandle&) = delete; 18 | ChildProcessHandle(ChildProcessHandle&& other) noexcept; 19 | 20 | ~ChildProcessHandle() noexcept; 21 | 22 | ChildProcessHandle& operator=(const ChildProcessHandle&) = delete; 23 | ChildProcessHandle& operator=(ChildProcessHandle&& other) noexcept; 24 | 25 | private: 26 | int pid_{-1}; 27 | 28 | void KillChild() noexcept; 29 | }; 30 | } // namespace lightstep 31 | -------------------------------------------------------------------------------- /benchmark/tracer_upload_bench/span.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "benchmark/tracer_upload_bench/tracer_upload_bench.pb.h" 4 | 5 | #include "opentracing/tracer.h" 6 | 7 | namespace lightstep { 8 | /** 9 | * Computes the approximate serialization size of a span in bytes with the given 10 | * configuration. 11 | * @param config the benchmark's configuration 12 | * @return the approximate size of a span 13 | */ 14 | size_t ComputeSpanSize(const tracer_upload_bench::Configuration& config); 15 | 16 | /** 17 | * Generate spans using the given tracer. 18 | * @param tracer the tracer to generate spans with 19 | * @param config the configuration describing how to produce spans 20 | */ 21 | void GenerateSpans(opentracing::Tracer& tracer, 22 | const tracer_upload_bench::Configuration& config); 23 | } // namespace lightstep 24 | -------------------------------------------------------------------------------- /benchmark/BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "//bazel:lightstep_build_system.bzl", 3 | "lightstep_google_benchmark", 4 | "lightstep_package", 5 | ) 6 | 7 | lightstep_google_benchmark( 8 | name = "span_operations_benchmark", 9 | srcs = [ 10 | "span_operations_benchmark.cpp", 11 | ], 12 | deps = [ 13 | "//:tracer_lib", 14 | ], 15 | ) 16 | 17 | lightstep_google_benchmark( 18 | name = "manual_tracer_benchmark", 19 | srcs = [ 20 | "manual_tracer_benchmark.cpp", 21 | ], 22 | deps = [ 23 | "//:tracer_lib", 24 | ], 25 | ) 26 | 27 | lightstep_google_benchmark( 28 | name = "buffer_benchmark", 29 | srcs = [ 30 | "buffer_benchmark.cpp", 31 | ], 32 | deps = [ 33 | "//src/common:circular_buffer_lib", 34 | "//test:baseline_circular_buffer_lib", 35 | ], 36 | ) 37 | -------------------------------------------------------------------------------- /test/network/socket_test.cpp: -------------------------------------------------------------------------------- 1 | #include "network/socket.h" 2 | 3 | #include "3rd_party/catch2/catch.hpp" 4 | 5 | using namespace lightstep; 6 | 7 | TEST_CASE("Socket") { 8 | SECTION("Socket can be move constructed.") { 9 | Socket s1; 10 | auto file_descriptor = s1.file_descriptor(); 11 | Socket s2{std::move(s1)}; 12 | CHECK(s2.file_descriptor() == file_descriptor); 13 | CHECK(s1.file_descriptor() == -1); 14 | } 15 | 16 | SECTION("Socket can be move assigned.") { 17 | Socket s1, s2; 18 | auto file_descriptor = s1.file_descriptor(); 19 | s2 = std::move(s1); 20 | REQUIRE(s2.file_descriptor() == file_descriptor); 21 | REQUIRE(s1.file_descriptor() == -1); 22 | } 23 | 24 | SECTION("We can change options on a socket.") { 25 | Socket s1; 26 | s1.SetNonblocking(); 27 | s1.SetReuseAddress(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /benchmark/tracer_upload_bench/BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "//bazel:lightstep_build_system.bzl", 3 | "lightstep_package", 4 | "lightstep_cc_binary", 5 | "lightstep_portable_cc_binary", 6 | ) 7 | 8 | lightstep_package() 9 | 10 | proto_library( 11 | name = "tracer_upload_bench_proto", 12 | srcs = ["tracer_upload_bench.proto"], 13 | deps = [ 14 | "//lightstep-tracer-configuration:tracer_configuration_proto", 15 | ], 16 | ) 17 | 18 | lightstep_portable_cc_binary( 19 | name = "tracer_upload_bench", 20 | srcs = glob(["*.h", "*.cpp"]), 21 | deps = [ 22 | "//:tracer_lib", 23 | "//test/recorder:in_memory_recorder_lib", 24 | ":tracer_upload_bench_proto_cc", 25 | ], 26 | ) 27 | 28 | cc_proto_library( 29 | name = "tracer_upload_bench_proto_cc", 30 | deps = [":tracer_upload_bench_proto"], 31 | ) 32 | 33 | -------------------------------------------------------------------------------- /bridge/python/binary/py27m/BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "//bazel:lightstep_build_system.bzl", 3 | "lightstep_portable_cc_binary", 4 | "lightstep_package", 5 | ) 6 | 7 | lightstep_package() 8 | 9 | lightstep_portable_cc_binary( 10 | name = "lightstep_streaming.so", 11 | linkshared = True, 12 | srcs = [ 13 | "//bridge/python/src:module.cpp", 14 | ], 15 | copts = [ 16 | "-Wno-missing-field-initializers", 17 | ], 18 | linkopts = [ 19 | "-Wl,--version-script=$(location :lightstep-export-map.ld)", 20 | ], 21 | deps = [ 22 | ":lightstep-export-map.ld", 23 | "//bridge/python:python_tracer_lib", 24 | ], 25 | external_deps = [ 26 | "@com_github_lightstep_python_bridge_tracer//:bridge_tracer_lib_py27m", 27 | ], 28 | visibility = [ 29 | "//visibility:public", 30 | ], 31 | ) 32 | -------------------------------------------------------------------------------- /bridge/python/binary/py3/BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "//bazel:lightstep_build_system.bzl", 3 | "lightstep_portable_cc_binary", 4 | "lightstep_package", 5 | ) 6 | 7 | lightstep_package() 8 | 9 | lightstep_portable_cc_binary( 10 | name = "lightstep_streaming.so", 11 | linkshared = True, 12 | srcs = [ 13 | "//bridge/python/src:module.cpp", 14 | ], 15 | copts = [ 16 | "-Wno-missing-field-initializers", 17 | ], 18 | linkopts = [ 19 | "-Wl,--version-script=$(location :lightstep-export-map.ld)", 20 | ], 21 | deps = [ 22 | ":lightstep-export-map.ld", 23 | "//bridge/python:python_tracer_lib", 24 | ], 25 | external_deps = [ 26 | "@com_github_lightstep_python_bridge_tracer//:bridge_tracer_lib_py3", 27 | ], 28 | visibility = [ 29 | "//visibility:public", 30 | ], 31 | ) 32 | -------------------------------------------------------------------------------- /ci/setup_build_environment.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | apt-get update 5 | apt-get install --no-install-recommends --no-install-suggests -y \ 6 | build-essential \ 7 | cmake \ 8 | pkg-config \ 9 | git \ 10 | ca-certificates \ 11 | curl \ 12 | automake \ 13 | autogen \ 14 | autoconf \ 15 | libtool \ 16 | gnupg2 \ 17 | ssh \ 18 | lcov \ 19 | vim \ 20 | gdb \ 21 | wget \ 22 | python python-setuptools python-pip \ 23 | zlib1g-dev \ 24 | libffi-dev \ 25 | python3 \ 26 | zip \ 27 | gettext-base 28 | pip install wheel 29 | -------------------------------------------------------------------------------- /bridge/python/binary/py27mu/BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "//bazel:lightstep_build_system.bzl", 3 | "lightstep_portable_cc_binary", 4 | "lightstep_package", 5 | ) 6 | 7 | lightstep_package() 8 | 9 | lightstep_portable_cc_binary( 10 | name = "lightstep_streaming.so", 11 | linkshared = True, 12 | srcs = [ 13 | "//bridge/python/src:module.cpp", 14 | ], 15 | copts = [ 16 | "-Wno-missing-field-initializers", 17 | ], 18 | linkopts = [ 19 | "-Wl,--version-script=$(location :lightstep-export-map.ld)", 20 | ], 21 | deps = [ 22 | ":lightstep-export-map.ld", 23 | "//bridge/python:python_tracer_lib", 24 | ], 25 | external_deps = [ 26 | "@com_github_lightstep_python_bridge_tracer//:bridge_tracer_lib_py27mu", 27 | ], 28 | visibility = [ 29 | "//visibility:public", 30 | ], 31 | ) 32 | -------------------------------------------------------------------------------- /test/recorder/serialization/report_request_header_test.cpp: -------------------------------------------------------------------------------- 1 | #include "recorder/serialization/report_request_header.h" 2 | 3 | #include "3rd_party/catch2/catch.hpp" 4 | #include "lightstep-tracer-common/collector.pb.h" 5 | using namespace lightstep; 6 | 7 | TEST_CASE("WriteReportRequestHeader") { 8 | LightStepTracerOptions tracer_options; 9 | tracer_options.access_token = "abc123"; 10 | tracer_options.tags = {{"xyz", 456}}; 11 | auto serialization = WriteReportRequestHeader(tracer_options, 789); 12 | collector::ReportRequest report; 13 | REQUIRE(report.ParseFromString(serialization)); 14 | REQUIRE(report.auth().access_token() == "abc123"); 15 | REQUIRE(report.reporter().reporter_id() == 789); 16 | auto& tags = report.reporter().tags(); 17 | REQUIRE(tags.size() == 1); 18 | REQUIRE(tags[0].key() == "xyz"); 19 | REQUIRE(tags[0].int_value() == 456); 20 | } 21 | -------------------------------------------------------------------------------- /benchmark/tracer_upload_bench/utility.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "benchmark/tracer_upload_bench/tracer_upload_bench.pb.h" 6 | #include "lightstep/tracer.h" 7 | #include "span_drop_counter.h" 8 | 9 | namespace lightstep { 10 | /** 11 | * Parse the benchmark's configuration from a file. 12 | * @param filename the file containing the benchmark's configuration 13 | * @return the benchmark configuration 14 | */ 15 | tracer_upload_bench::Configuration ParseConfiguration(const char* filename); 16 | 17 | /** 18 | * Construct a tracer with the provided configuration. 19 | * @param config the configuration for the tracer 20 | * @return the tracer and dropped span recorder 21 | */ 22 | std::tuple, SpanDropCounter*> MakeTracer( 23 | const tracer_upload_bench::Configuration& config); 24 | } // namespace lightstep 25 | -------------------------------------------------------------------------------- /ci/clone_lightstep_benchmarks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | REPO_URL="https://github.com/lightstep/lightstep-benchmarks.git" 6 | MAJOR_VERSION="0" 7 | 8 | # clone the repo 9 | git clone ${REPO_URL} 10 | cd lightstep-benchmarks 11 | 12 | # copy the tags to the local repo (from all remotes) 13 | git fetch --all --tags 14 | 15 | # find most recent release whose tag matches the specified major / minor 16 | # version 17 | MATCHING_VERSIONS=`git tag --sort -version:refname --list "v${MAJOR_VERSION}.*.*" | tr '\n' ','` 18 | NEWEST_VERSION=`echo ${MATCHING_VERSIONS} | cut -d ',' -f 1` 19 | 20 | echo "versions, newest to oldest: ${MATCHING_VERSIONS}" 21 | echo "newest version: ${NEWEST_VERSION}" 22 | 23 | # checkout the code corresponding to the newest tag 24 | git checkout tags/${NEWEST_VERSION} 25 | 26 | # so that we can confirm everything is a-okay 27 | git branch; git tag 28 | -------------------------------------------------------------------------------- /ci/do_ci.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = "Stop"; 2 | trap { $host.SetShouldExit(1) } 3 | 4 | $action = $args[0] 5 | 6 | $SRC_DIR=(Get-Item -Path ".\").FullName 7 | mkdir build 8 | $BUILD_DIR="$SRC_DIR\build" 9 | $VCPKG_DIR="$SRC_DIR\vcpkg" 10 | 11 | switch ($action) { 12 | "build" { 13 | cd "$BUILD_DIR" 14 | cmake $SRC_DIR ` 15 | -DVCPKG_TARGET_TRIPLET=x64-windows-static ` 16 | "-DCMAKE_TOOLCHAIN_FILE=$VCPKG_DIR\scripts\buildsystems\vcpkg.cmake" ` 17 | -DBUILD_SHARED_LIBS=OFF ` 18 | -DWITH_DYNAMIC_LOAD=OFF ` 19 | -DWITH_GRPC=OFF ` 20 | -DWITH_LIBEVENT=ON 21 | $exit = $LASTEXITCODE 22 | if ($exit -ne 0) { 23 | exit $exit 24 | } 25 | cmake --build . 26 | $exit = $LASTEXITCODE 27 | if ($exit -ne 0) { 28 | exit $exit 29 | } 30 | } 31 | default { 32 | echo "unknown action: $action" 33 | exit 1 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /bazel/profile_benchmark.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | BENCHMARK=$1 6 | OUTPUT=$2 7 | VALGRIND=$3 8 | DOT=$4 9 | GPROF2DOT=$5 10 | BENCHMARK_NAME=$(basename $BENCHMARK) 11 | BENCHMARKS=$($BENCHMARK --benchmark_list_tests) 12 | TEMPDIR=$(mktemp -d) 13 | echo $TEMPDIR 14 | pushd $TEMPDIR 15 | for FILTER in $BENCHMARKS; do 16 | FILTER_PRIME=$(echo $FILTER | tr / -) 17 | echo "Generate profile for $FILTER" 18 | $VALGRIND --tool=callgrind $BENCHMARK --benchmark_filter=$FILTER$ 19 | echo "Convert $FILTER to image" 20 | $GPROF2DOT --format=callgrind --output=$BENCHMARK_NAME-$FILTER_PRIME.dot callgrind.out.[0-9]* 21 | $DOT -Tsvg $BENCHMARK_NAME-$FILTER_PRIME.dot -o "$BENCHMARK_NAME-$FILTER_PRIME.svg" 22 | mv callgrind.out.[0-9]* callgrind.out.$BENCHMARK_NAME-$FILTER_PRIME 23 | tar zcf $(basename $OUTPUT) *.svg *.dot callgrind.out.* 24 | done 25 | popd 26 | mv $TEMPDIR/$(basename $OUTPUT) $OUTPUT 27 | -------------------------------------------------------------------------------- /src/common/chunked_http_framing.cpp: -------------------------------------------------------------------------------- 1 | #include "common/chunked_http_framing.h" 2 | 3 | namespace lightstep { 4 | //-------------------------------------------------------------------------------------------------- 5 | // WriteHttpChunkHeader 6 | //-------------------------------------------------------------------------------------------------- 7 | size_t WriteHttpChunkHeader(char* data, size_t size, 8 | uint32_t chunk_size) noexcept { 9 | assert(size >= ChunkedHttpMaxHeaderSize); 10 | auto serialization_start = data + (size - ChunkedHttpMaxHeaderSize); 11 | auto chunk_size_str = 12 | Uint32ToHex(static_cast(chunk_size), serialization_start); 13 | assert(chunk_size_str.size() == Num32BitHexDigits); 14 | auto iter = serialization_start + chunk_size_str.size(); 15 | *iter++ = '\r'; 16 | *iter++ = '\n'; 17 | return ChunkedHttpMaxHeaderSize; 18 | } 19 | } // namespace lightstep 20 | -------------------------------------------------------------------------------- /src/tracer/propagation/binary_propagation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "tracer/propagation/propagator.h" 6 | 7 | #include 8 | #include 9 | 10 | namespace lightstep { 11 | template 12 | opentracing::expected InjectSpanContext(std::ostream& carrier, 13 | uint64_t trace_id, 14 | uint64_t span_id, bool sampled, 15 | const BaggageMap& baggage); 16 | 17 | opentracing::expected ExtractSpanContext(std::istream& carrier, 18 | uint64_t& trace_id, 19 | uint64_t& span_id, bool& sampled, 20 | BaggageProtobufMap& baggage); 21 | 22 | } // namespace lightstep 23 | -------------------------------------------------------------------------------- /src/common/buffer_chain.cpp: -------------------------------------------------------------------------------- 1 | #include "lightstep/buffer_chain.h" 2 | 3 | #include 4 | #include 5 | 6 | namespace lightstep { 7 | //-------------------------------------------------------------------------------------------------- 8 | // CopyOut 9 | //-------------------------------------------------------------------------------------------------- 10 | void BufferChain::CopyOut(char* data, size_t length) const noexcept { 11 | if (length < this->num_bytes()) { 12 | std::terminate(); 13 | } 14 | auto callback = [](void* context, const void* fragment_data, 15 | size_t fragment_size) noexcept { 16 | auto out = static_cast(context); 17 | *out = std::copy_n(static_cast(fragment_data), fragment_size, 18 | *out); 19 | return true; 20 | }; 21 | this->ForEachFragment(callback, static_cast(&data)); 22 | } 23 | } // namespace lightstep 24 | -------------------------------------------------------------------------------- /test/mock_dns_server/BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "//bazel:lightstep_build_system.bzl", 3 | "lightstep_package", 4 | "lightstep_cc_library", 5 | "lightstep_go_binary", 6 | ) 7 | 8 | lightstep_package() 9 | 10 | lightstep_go_binary( 11 | name = "mock_dns_server", 12 | srcs = [ 13 | "main.go", 14 | ], 15 | out = "mock_dns_server", 16 | deps = [ 17 | "@com_github_miekg_dns//:go_default_library", 18 | ], 19 | ) 20 | 21 | lightstep_cc_library( 22 | name = "mock_dns_server_lib", 23 | private_hdrs = [ 24 | "mock_dns_server_handle.h", 25 | ], 26 | srcs = [ 27 | "mock_dns_server_handle.cpp", 28 | ], 29 | deps = [ 30 | "//test:child_process_handle_lib", 31 | "//test:utility_lib", 32 | "//test:mock_dns_resolution_callback_lib", 33 | "//src/network/ares_dns_resolver:ares_dns_resolver_lib", 34 | ], 35 | data = [ 36 | ":mock_dns_server", 37 | ], 38 | ) 39 | -------------------------------------------------------------------------------- /include/lightstep/metrics_observer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace lightstep { 4 | // MetricsObserver can be used to track LightStep tracer events. 5 | class MetricsObserver { 6 | public: 7 | MetricsObserver() noexcept = default; 8 | 9 | MetricsObserver(const MetricsObserver&) noexcept = default; 10 | 11 | MetricsObserver(MetricsObserver&&) noexcept = default; 12 | 13 | virtual ~MetricsObserver() = default; 14 | 15 | MetricsObserver& operator=(const MetricsObserver&) noexcept = default; 16 | MetricsObserver& operator=(MetricsObserver&&) noexcept = default; 17 | 18 | // OnSpansSent records spans transported. 19 | virtual void OnSpansSent(int /*num_spans*/) noexcept {} 20 | 21 | // OnSpansDropped records spans dropped. 22 | virtual void OnSpansDropped(int /*num_spans*/) noexcept {} 23 | 24 | // OnFlush records flush events by the recorder. 25 | virtual void OnFlush() noexcept {} 26 | }; 27 | } // namespace lightstep 28 | -------------------------------------------------------------------------------- /src/recorder/stream_recorder/host_header.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "lightstep/tracer.h" 6 | 7 | namespace lightstep { 8 | /** 9 | * Manages the host header in a streaming HTTP POST request. 10 | */ 11 | class HostHeader { 12 | public: 13 | explicit HostHeader(const LightStepTracerOptions& tracer_options); 14 | 15 | /** 16 | * Sets the host to send in the header. 17 | * @param host the host to set. 18 | * 19 | * Note: host must hvae been specified in LightStepTracerOptions. 20 | */ 21 | void set_host(const char* host) noexcept; 22 | 23 | /** 24 | * @return the fragment for the host header. 25 | * 26 | * Note: The fragment remains the same even if set_host is called with a 27 | * different host. 28 | */ 29 | std::pair fragment() const noexcept; 30 | 31 | private: 32 | std::string format_; 33 | std::vector header_; 34 | }; 35 | } // namespace lightstep 36 | -------------------------------------------------------------------------------- /src/common/in_memory_stream.cpp: -------------------------------------------------------------------------------- 1 | #include "common/in_memory_stream.h" 2 | 3 | namespace lightstep { 4 | //------------------------------------------------------------------------------ 5 | // in_memory_buffer constructor 6 | //------------------------------------------------------------------------------ 7 | in_memory_buffer::in_memory_buffer(const char* data, size_t size) { 8 | // Data isn't modified so this is safe. 9 | auto non_const_data = const_cast(data); 10 | setg(non_const_data, non_const_data, non_const_data + size); 11 | } 12 | 13 | //------------------------------------------------------------------------------ 14 | // in_memory_stream constructor 15 | //------------------------------------------------------------------------------ 16 | in_memory_stream::in_memory_stream(const char* data, size_t size) 17 | : in_memory_buffer{data, size}, 18 | std::istream{static_cast(this)} {} 19 | } // namespace lightstep 20 | -------------------------------------------------------------------------------- /test/recorder/serialization/embedded_metrics_message_test.cpp: -------------------------------------------------------------------------------- 1 | #include "recorder/serialization/embedded_metrics_message.h" 2 | 3 | #include "3rd_party/catch2/catch.hpp" 4 | using namespace lightstep; 5 | 6 | TEST_CASE("EmbeddedMetricsMessage") { 7 | EmbeddedMetricsMessage metrics_message; 8 | metrics_message.set_num_dropped_spans(3); 9 | REQUIRE(metrics_message.num_dropped_spans() == 3); 10 | auto fragment = metrics_message.MakeFragment(); 11 | 12 | SECTION("The metrics fragment can be deserialized by protobuf.") { 13 | collector::ReportRequest report; 14 | REQUIRE(report.ParseFromArray(fragment.first, 15 | static_cast(fragment.second))); 16 | REQUIRE(report.internal_metrics().counts().size() == 1); 17 | auto& dropped_span_count = report.internal_metrics().counts()[0]; 18 | REQUIRE(dropped_span_count.name() == "spans.dropped"); 19 | REQUIRE(dropped_span_count.int_value() == 3); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/common/report_request_framing.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "common/serialization.h" 6 | 7 | namespace lightstep { 8 | constexpr size_t ReportRequestSpansField = 3; 9 | 10 | constexpr size_t ReportRequestSpansMaxHeaderSize = 11 | StaticKeySerializationSize::value + 13 | google::protobuf::io::CodedOutputStream::StaticVarintSize32< 14 | std::numeric_limits::max()>::value; 15 | 16 | /** 17 | * Write framing for a span in a collector::ReportRequest message. 18 | * @param data start of the buffer to write to. 19 | * @param size the size of the buffer 20 | * @param chunk_size the size of the chunk. 21 | * 22 | * Note: Data is written from the end of the provided buffer. 23 | */ 24 | size_t WriteReportRequestSpansHeader(char* data, size_t size, 25 | uint32_t body_size) noexcept; 26 | } // namespace lightstep 27 | -------------------------------------------------------------------------------- /test/string_logger_sink.cpp: -------------------------------------------------------------------------------- 1 | #include "test/string_logger_sink.h" 2 | 3 | namespace lightstep { 4 | //-------------------------------------------------------------------------------------------------- 5 | // operator() 6 | //-------------------------------------------------------------------------------------------------- 7 | void StringLoggerSink::operator()(LogLevel log_level, 8 | opentracing::string_view message) noexcept { 9 | std::lock_guard log_guard{mutex_}; 10 | oss_ << "Level " << static_cast(log_level) << ": " << message << "\n"; 11 | } 12 | 13 | //-------------------------------------------------------------------------------------------------- 14 | // contents 15 | //-------------------------------------------------------------------------------------------------- 16 | std::string StringLoggerSink::contents() { 17 | std::lock_guard log_guard{mutex_}; 18 | return oss_.str(); 19 | } 20 | } // namespace lightstep 21 | -------------------------------------------------------------------------------- /test/common/spin_lock_mutex_test.cpp: -------------------------------------------------------------------------------- 1 | #include "common/spin_lock_mutex.h" 2 | 3 | #include 4 | 5 | #include "3rd_party/catch2/catch.hpp" 6 | using namespace lightstep; 7 | 8 | static void AddNumbers(SpinLockMutex& mutex, int a, int b, 9 | std::vector& v) { 10 | for (int i = a; i < b; ++i) { 11 | SpinLockGuard lock_guard{mutex}; 12 | v.push_back(i); 13 | } 14 | } 15 | 16 | TEST_CASE("SpinLockMutex") { 17 | std::vector v; 18 | std::vector threads(4); 19 | SpinLockMutex mutex; 20 | int a = 0; 21 | int n = 5000; 22 | for (auto& thread : threads) { 23 | thread = std::thread{AddNumbers, std::ref(mutex), a, a + n, std::ref(v)}; 24 | a += n; 25 | } 26 | for (auto& thread : threads) { 27 | thread.join(); 28 | } 29 | std::sort(v.begin(), v.end()); 30 | REQUIRE(v.size() == static_cast(n * threads.size())); 31 | int index = 0; 32 | for (auto value : v) { 33 | REQUIRE(value == index++); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/common/report_request_framing.cpp: -------------------------------------------------------------------------------- 1 | #include "common/report_request_framing.h" 2 | 3 | #include 4 | 5 | namespace lightstep { 6 | //-------------------------------------------------------------------------------------------------- 7 | // WriteReportRequestSpansHeader 8 | //-------------------------------------------------------------------------------------------------- 9 | size_t WriteReportRequestSpansHeader(char* data, size_t size, 10 | uint32_t body_size) noexcept { 11 | assert(size >= ReportRequestSpansMaxHeaderSize); 12 | auto header_size = 13 | ComputeLengthDelimitedHeaderSerializationSize( 14 | body_size); 15 | auto serialization_start = data + (size - header_size); 16 | DirectCodedOutputStream stream{ 17 | reinterpret_cast(serialization_start)}; 18 | WriteKeyLength(stream, body_size); 19 | return header_size; 20 | } 21 | } // namespace lightstep 22 | -------------------------------------------------------------------------------- /test/common/timestamp_test.cpp: -------------------------------------------------------------------------------- 1 | #include "common/timestamp.h" 2 | 3 | #include 4 | 5 | #include "3rd_party/catch2/catch.hpp" 6 | using namespace lightstep; 7 | 8 | TEST_CASE( 9 | "A system-steady timestamp delta can be used to convert between the " 10 | "different timestamps") { 11 | auto timestamp_delta = ComputeSystemSteadyTimestampDelta(); 12 | auto system_now = std::chrono::system_clock::now(); 13 | auto steady_now = std::chrono::steady_clock::now(); 14 | 15 | auto system_now_prime = ToSystemTimestamp(timestamp_delta, steady_now); 16 | auto steady_now_prime = ToSteadyTimestamp(timestamp_delta, system_now); 17 | 18 | REQUIRE(std::abs(std::chrono::duration_cast( 19 | system_now_prime - system_now) 20 | .count()) < 100); 21 | 22 | REQUIRE(std::abs(std::chrono::duration_cast( 23 | steady_now_prime - steady_now) 24 | .count()) < 100); 25 | } 26 | -------------------------------------------------------------------------------- /test/tracer/propagation/http_headers_carrier.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace lightstep { 8 | class HTTPHeadersCarrier : public opentracing::HTTPHeadersReader, 9 | public opentracing::HTTPHeadersWriter { 10 | public: 11 | explicit HTTPHeadersCarrier( 12 | std::unordered_map& text_map_); 13 | 14 | // opentracing::HTPPHeadersReader 15 | opentracing::expected ForeachKey( 16 | std::function(opentracing::string_view key, 17 | opentracing::string_view value)> 18 | f) const override; 19 | 20 | // opentracing::HTTPHeadersWriter 21 | opentracing::expected Set( 22 | opentracing::string_view key, 23 | opentracing::string_view value) const override; 24 | 25 | private: 26 | std::unordered_map& text_map; 27 | }; 28 | } // namespace lightstep 29 | -------------------------------------------------------------------------------- /include/lightstep/binary_carrier.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "lightstep-tracer-common/lightstep_carrier.pb.h" 5 | 6 | namespace lightstep { 7 | class LightStepBinaryReader : public opentracing::CustomCarrierReader { 8 | public: 9 | explicit LightStepBinaryReader(const BinaryCarrier* carrier) noexcept 10 | : carrier_{carrier} {} 11 | 12 | opentracing::expected> Extract( 13 | const opentracing::Tracer& tracer) const override; 14 | 15 | private: 16 | const BinaryCarrier* carrier_; 17 | }; 18 | 19 | class LightStepBinaryWriter : public opentracing::CustomCarrierWriter { 20 | public: 21 | LightStepBinaryWriter(BinaryCarrier& carrier) noexcept : carrier_{carrier} {} 22 | 23 | opentracing::expected Inject( 24 | const opentracing::Tracer& tracer, 25 | const opentracing::SpanContext& span_context) const override; 26 | 27 | private: 28 | BinaryCarrier& carrier_; 29 | }; 30 | } // namespace lightstep 31 | -------------------------------------------------------------------------------- /src/tracer/propagation/trace_context_propagator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "tracer/propagation/propagator.h" 4 | 5 | namespace lightstep { 6 | class TraceContextPropagator final : public Propagator { 7 | public: 8 | // Propagator 9 | opentracing::expected InjectSpanContext( 10 | const opentracing::TextMapWriter& carrier, 11 | const TraceContext& trace_context, opentracing::string_view trace_state, 12 | const BaggageProtobufMap& baggage) const override; 13 | 14 | opentracing::expected InjectSpanContext( 15 | const opentracing::TextMapWriter& carrier, 16 | const TraceContext& trace_context, opentracing::string_view trace_state, 17 | const BaggageFlatMap& baggage) const override; 18 | 19 | opentracing::expected ExtractSpanContext( 20 | const opentracing::TextMapReader& carrier, bool case_sensitive, 21 | TraceContext& trace_context, std::string& trace_state, 22 | BaggageProtobufMap& baggage) const override; 23 | }; 24 | } // namespace lightstep 25 | -------------------------------------------------------------------------------- /src/recorder/serialization/embedded_metrics_message.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "lightstep-tracer-common/collector.pb.h" 7 | 8 | namespace lightstep { 9 | /** 10 | * Manages the metrics message sent in a ReportRequest. 11 | */ 12 | class EmbeddedMetricsMessage { 13 | public: 14 | EmbeddedMetricsMessage(); 15 | 16 | /** 17 | * Sets the number of dropped spans to send in the message. 18 | * @param num_dropped_spans the number of dropped spans to set. 19 | */ 20 | void set_num_dropped_spans(int num_dropped_spans) const noexcept; 21 | 22 | /** 23 | * @return the number of dropped spans in the message. 24 | */ 25 | int num_dropped_spans() const noexcept; 26 | 27 | /** 28 | * @return a fragment for the serialized message. 29 | */ 30 | std::pair MakeFragment(); 31 | 32 | private: 33 | collector::InternalMetrics message_; 34 | collector::MetricsSample& dropped_spans_count_; 35 | std::vector buffer_; 36 | }; 37 | } // namespace lightstep 38 | -------------------------------------------------------------------------------- /test/common/atomic_unique_ptr_test.cpp: -------------------------------------------------------------------------------- 1 | #include "common/atomic_unique_ptr.h" 2 | 3 | #include "3rd_party/catch2/catch.hpp" 4 | using namespace lightstep; 5 | 6 | TEST_CASE("AtomicUniquePtr") { 7 | AtomicUniquePtr ptr; 8 | REQUIRE(ptr.IsNull()); 9 | 10 | SECTION("SwapIfNull swaps an AtomicUniquePtr is null") { 11 | std::unique_ptr x{new int{33}}; 12 | REQUIRE(ptr.SwapIfNull(x)); 13 | REQUIRE(x == nullptr); 14 | REQUIRE(*ptr == 33); 15 | } 16 | 17 | SECTION("SwapIfNull does nothing if AtomicUniquePtr is non-null") { 18 | ptr.Reset(new int{11}); 19 | std::unique_ptr x{new int{33}}; 20 | REQUIRE(!ptr.SwapIfNull(x)); 21 | REQUIRE(x != nullptr); 22 | REQUIRE(*x == 33); 23 | REQUIRE(*ptr == 11); 24 | } 25 | 26 | SECTION("Swap always swaps an AtomicUniquePtr") { 27 | ptr.Reset(new int{11}); 28 | std::unique_ptr x{new int{33}}; 29 | ptr.Swap(x); 30 | REQUIRE(!ptr.IsNull()); 31 | REQUIRE(x != nullptr); 32 | REQUIRE(*x == 11); 33 | REQUIRE(*ptr == 33); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/tracer/propagation/b3_propagator.cpp: -------------------------------------------------------------------------------- 1 | #include "tracer/propagation/b3_propagator.h" 2 | 3 | #include "tracer/propagation/lightstep_propagator.h" 4 | #include "tracer/propagation/multiheader_propagator.h" 5 | 6 | #define PREFIX_TRACER_STATE "X-B3-" 7 | const opentracing::string_view FieldNameTraceID = PREFIX_TRACER_STATE "TraceId"; 8 | const opentracing::string_view FieldNameSpanID = PREFIX_TRACER_STATE "SpanId"; 9 | const opentracing::string_view FieldNameSampled = PREFIX_TRACER_STATE "Sampled"; 10 | #undef PREFIX_TRACER_STATE 11 | 12 | namespace lightstep { 13 | //-------------------------------------------------------------------------------------------------- 14 | // MakeB3Propagator 15 | //-------------------------------------------------------------------------------------------------- 16 | std::unique_ptr MakeB3Propagator() { 17 | return std::unique_ptr{ 18 | new MultiheaderPropagator{FieldNameTraceID, FieldNameSpanID, 19 | FieldNameSampled, PrefixBaggage, true}}; 20 | } 21 | } // namespace lightstep 22 | -------------------------------------------------------------------------------- /src/common/timestamp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace lightstep { 7 | /** 8 | * Computes a delta between the steady and system clocks that can be used for 9 | * timestamp conversions. 10 | * @return the timestamp delta 11 | */ 12 | int64_t ComputeSystemSteadyTimestampDelta() noexcept; 13 | 14 | /** 15 | * Convert a steady time point to a system time point 16 | * @param timestamp_delta the system-steady timestamp delta 17 | * @param steady_timestamp the steady timestamp 18 | */ 19 | std::chrono::system_clock::time_point ToSystemTimestamp( 20 | int64_t timestamp_delta, 21 | std::chrono::steady_clock::time_point steady_timestamp) noexcept; 22 | 23 | /** 24 | * Convert a system time point to a steady time point 25 | * @param timestamp_delta the system-steady timestamp delta 26 | * @param system_timestamp the system timestamp 27 | */ 28 | std::chrono::steady_clock::time_point ToSteadyTimestamp( 29 | int64_t timestamp_delta, 30 | std::chrono::system_clock::time_point system_timestamp) noexcept; 31 | } // namespace lightstep 32 | -------------------------------------------------------------------------------- /test/recorder/serialization/BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "//bazel:lightstep_build_system.bzl", 3 | "lightstep_catch_test", 4 | "lightstep_cc_library", 5 | "lightstep_package", 6 | ) 7 | 8 | lightstep_package() 9 | 10 | lightstep_catch_test( 11 | name = "report_request_header_test", 12 | srcs = [ 13 | "report_request_header_test.cpp", 14 | ], 15 | deps = [ 16 | "//src/recorder/serialization:report_request_header_lib", 17 | ], 18 | ) 19 | 20 | lightstep_catch_test( 21 | name = "embedded_metrics_message_test", 22 | srcs = [ 23 | "embedded_metrics_message_test.cpp", 24 | ], 25 | deps = [ 26 | "//src/recorder/serialization:embedded_metrics_message_lib", 27 | ], 28 | ) 29 | 30 | lightstep_catch_test( 31 | name = "report_request_test", 32 | srcs = [ 33 | "report_request_test.cpp", 34 | ], 35 | deps = [ 36 | "//src/common:report_request_framing_lib", 37 | "//src/recorder/serialization:report_request_lib", 38 | "//src/recorder/serialization:report_request_header_lib", 39 | ], 40 | ) 41 | -------------------------------------------------------------------------------- /src/tracer/propagation/trace_context.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace lightstep { 9 | const size_t TraceContextLength = 55; 10 | const uint8_t SampledFlagMask = 1; 11 | const uint8_t TraceContextVersion = 0; 12 | 13 | struct TraceContext { 14 | uint64_t trace_id_high{0}; 15 | uint64_t trace_id_low{0}; 16 | uint64_t parent_id{0}; 17 | uint8_t trace_flags{0}; 18 | uint8_t version{TraceContextVersion}; 19 | }; 20 | 21 | opentracing::expected ParseTraceContext( 22 | opentracing::string_view s, TraceContext& trace_context) noexcept; 23 | 24 | void SerializeTraceContext(const TraceContext& trace_context, char* s) noexcept; 25 | 26 | template 27 | inline bool IsTraceFlagSet(uint8_t flags) noexcept { 28 | return static_cast(flags & Mask); 29 | } 30 | 31 | template 32 | inline uint8_t SetTraceFlag(uint8_t flags, bool value) noexcept { 33 | if (value) { 34 | return flags | Mask; 35 | } 36 | return flags & ~Mask; 37 | } 38 | } // namespace lightstep 39 | -------------------------------------------------------------------------------- /test/zero_copy_connection_input_stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "recorder/stream_recorder/connection_stream.h" 4 | 5 | #include 6 | 7 | namespace lightstep { 8 | /** 9 | * Wraps a ConnectionStream to expose a ZeroCopyInputStream interface. 10 | * 11 | * Reads bytes from the ConnectionStream in random amounts so as to simulate 12 | * different scenarios for testing. 13 | */ 14 | class ZeroCopyConnectionInputStream 15 | : public google::protobuf::io::ZeroCopyInputStream { 16 | public: 17 | explicit ZeroCopyConnectionInputStream(ConnectionStream& stream); 18 | 19 | // google::protobuf::io::ZeroCopyInputStream 20 | bool Next(const void** data, int* size) override; 21 | 22 | void BackUp(int count) override; 23 | 24 | bool Skip(int count) override; 25 | 26 | google::protobuf::int64 ByteCount() const override { return byte_count_; } 27 | 28 | private: 29 | ConnectionStream& stream_; 30 | std::string buffer_; 31 | google::protobuf::int64 byte_count_{0}; 32 | int position_{0}; 33 | 34 | void SetBuffer(); 35 | }; 36 | } // namespace lightstep 37 | -------------------------------------------------------------------------------- /src/tracer/lightstep_span_context.cpp: -------------------------------------------------------------------------------- 1 | #include "tracer/lightstep_span_context.h" 2 | 3 | namespace lightstep { 4 | //------------------------------------------------------------------------------ 5 | // operator== 6 | //------------------------------------------------------------------------------ 7 | bool operator==(const LightStepSpanContext& lhs, 8 | const LightStepSpanContext& rhs) { 9 | auto extract_baggage = [](const LightStepSpanContext& span_context) { 10 | std::unordered_map baggage; 11 | span_context.ForeachBaggageItem( 12 | [&](const std::string& key, const std::string& value) { 13 | baggage.emplace(key, value); 14 | return true; 15 | }); 16 | return baggage; 17 | }; 18 | 19 | return lhs.trace_id_high() == rhs.trace_id_high() && 20 | lhs.trace_id_low() == rhs.trace_id_low() && 21 | lhs.span_id() == rhs.span_id() && 22 | lhs.trace_state() == rhs.trace_state() && 23 | lhs.trace_flags() == rhs.trace_flags() && 24 | extract_baggage(lhs) == extract_baggage(rhs); 25 | } 26 | } // namespace lightstep 27 | -------------------------------------------------------------------------------- /test/bridge/python/tracer_test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import unittest 4 | 5 | for pyversion in os.listdir('bridge/python/binary'): 6 | sys.path.append('bridge/python/binary/' + pyversion) 7 | import lightstep_streaming 8 | 9 | class TestTracer(unittest.TestCase): 10 | def test_error_on_bad_config(self): 11 | with self.assertRaises(Exception): 12 | lightstep_streaming.Tracer() 13 | 14 | with self.assertRaises(Exception): 15 | lightstep_streaming.Tracer('abc') 16 | 17 | with self.assertRaises(Exception): 18 | lightstep_streaming.Tracer(xyz='abc') 19 | 20 | def test_report_span(self): 21 | tracer = lightstep_streaming.Tracer(access_token='abc', 22 | use_stream_recorder=True, 23 | collector_plaintext=True, 24 | satellite_endpoints=[{'host':'locahost', 'port':123}]) 25 | self.assertEqual(tracer.num_spans_sent, 0) 26 | self.assertEqual(tracer.num_spans_dropped, 0) 27 | 28 | 29 | if __name__ == '__main__': 30 | unittest.main() 31 | -------------------------------------------------------------------------------- /test/mock_dns_resolution_callback.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "network/dns_resolver.h" 4 | #include "network/event_base.h" 5 | 6 | namespace lightstep { 7 | /** 8 | * A dns resolution callback that captures everything provided. 9 | */ 10 | class MockDnsResolutionCallback final : public DnsResolutionCallback { 11 | public: 12 | explicit MockDnsResolutionCallback(EventBase& event_base) 13 | : event_base_{event_base} {} 14 | 15 | /** 16 | * @return the ip addresses provided by the dns resolution. 17 | */ 18 | const std::vector ip_addresses() const noexcept { 19 | return ip_addresses_; 20 | } 21 | 22 | /** 23 | * @return the error messages provied by the dns resolution. 24 | */ 25 | const std::string& error_message() const noexcept { return error_message_; } 26 | 27 | // DnsResolutionCallback 28 | void OnDnsResolution( 29 | const DnsResolution& resolution, 30 | opentracing::string_view error_message) noexcept override; 31 | 32 | private: 33 | EventBase& event_base_; 34 | std::string error_message_; 35 | std::vector ip_addresses_; 36 | }; 37 | } // namespace lightstep 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2016 LightStep 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /test/network/event_test.cpp: -------------------------------------------------------------------------------- 1 | #include "network/event.h" 2 | #include "network/event_base.h" 3 | 4 | #include "3rd_party/catch2/catch.hpp" 5 | 6 | using namespace lightstep; 7 | 8 | TEST_CASE("Event") { 9 | auto callback = [](int /*file_descriptor*/, short /*what*/, 10 | void* /*context*/) {}; 11 | 12 | EventBase event_base; 13 | Event event{event_base, -1, 0, callback, nullptr}; 14 | REQUIRE(event.libevent_handle() != nullptr); 15 | 16 | SECTION("Event can be default constructed.") { 17 | Event event; 18 | REQUIRE(event.libevent_handle() == nullptr); 19 | } 20 | 21 | SECTION("Event can be move constructed.") { 22 | auto handle = event.libevent_handle(); 23 | Event event2{std::move(event)}; 24 | REQUIRE(event2.libevent_handle() == handle); 25 | REQUIRE(event.libevent_handle() == nullptr); 26 | } 27 | 28 | SECTION("Event can be move assigned.") { 29 | Event event2{event_base, -1, 0, callback, nullptr}; 30 | auto handle = event.libevent_handle(); 31 | event2 = std::move(event); 32 | REQUIRE(event2.libevent_handle() == handle); 33 | REQUIRE(event.libevent_handle() == nullptr); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/composable_fragment_input_stream_wrapper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "common/composable_fragment_input_stream.h" 6 | 7 | namespace lightstep { 8 | /** 9 | * Wraps a FragmentInputStream to make it composable for testing. 10 | */ 11 | class ComposableFragmentInputStreamWrapper final 12 | : public ComposableFragmentInputStream { 13 | public: 14 | explicit ComposableFragmentInputStreamWrapper( 15 | std::unique_ptr&& stream) noexcept 16 | : stream_{std::move(stream)} {} 17 | 18 | // ComposableFragmentInputStream 19 | int segment_num_fragments() const noexcept override { 20 | return stream_->num_fragments(); 21 | } 22 | 23 | bool SegmentForEachFragment(Callback callback) const noexcept override { 24 | return stream_->ForEachFragment(callback); 25 | } 26 | 27 | void SegmentClear() noexcept override { return stream_->Clear(); } 28 | 29 | void SegmentSeek(int fragment_index, int position) noexcept override { 30 | return stream_->Seek(fragment_index, position); 31 | } 32 | 33 | private: 34 | std::unique_ptr stream_; 35 | }; 36 | } // namespace lightstep 37 | -------------------------------------------------------------------------------- /.bazelrc: -------------------------------------------------------------------------------- 1 | build:asan --define LIGHTSTEP_CONFIG_ASAN=1 2 | build:asan --copt -fsanitize=address 3 | build:asan --linkopt -fsanitize=address 4 | 5 | 6 | build:tsan --define LIGHTSTEP_CONFIG_TSAN=1 7 | build:tsan --copt -fsanitize=thread 8 | build:tsan --linkopt -fsanitize=thread 9 | 10 | # Needed due to https://github.com/libevent/libevent/issues/777 11 | build:tsan --copt -DEVENT__DISABLE_DEBUG_MODE 12 | 13 | build --copt -DPYTHON_BRIDGE_TRACER_MODULE="\"lightstep_native\"" 14 | 15 | # Fortifying the sources will lead to requiring glibc >= 2.15, so we turn fortifying off 16 | # See https://stackoverflow.com/a/20953117/4447365 17 | build:portable_glibc --copt -U_FORTIFY_SOURCE 18 | build:portable_glibc --copt -D_FORTIFY_SOURCE=0 19 | 20 | # Work around to a bug with the gold linker where it doesn't work properly with wrapping and symbol 21 | # versioning 22 | # See https://sourceware.org/bugzilla/show_bug.cgi?id=22628 23 | build:portable_glibc --nostart_end_lib 24 | build:portable_glibc --linkopt -fuse-ld=bfd 25 | 26 | build:portable_glibc --define LIGHTSTEP_PORTABLE_GLIBC=1 27 | 28 | build:static_libcpp --linkopt -static-libstdc++ 29 | build:static_libcpp --linkopt -static-libgcc 30 | -------------------------------------------------------------------------------- /src/tracer/propagation/lightstep_propagator.cpp: -------------------------------------------------------------------------------- 1 | #include "lightstep_propagator.h" 2 | 3 | #include "tracer/propagation/multiheader_propagator.h" 4 | 5 | #define PREFIX_TRACER_STATE "ot-tracer-" 6 | // Note: these constants are a convention of the OpenTracing basictracers. 7 | 8 | const opentracing::string_view FieldNameTraceID = PREFIX_TRACER_STATE "traceid"; 9 | const opentracing::string_view FieldNameSpanID = PREFIX_TRACER_STATE "spanid"; 10 | const opentracing::string_view FieldNameSampled = PREFIX_TRACER_STATE "sampled"; 11 | #undef PREFIX_TRACER_STATE 12 | 13 | namespace lightstep { 14 | const opentracing::string_view PrefixBaggage = "ot-baggage-"; 15 | 16 | //-------------------------------------------------------------------------------------------------- 17 | // MakeLightStepPropagator 18 | //-------------------------------------------------------------------------------------------------- 19 | std::unique_ptr MakeLightStepPropagator() { 20 | return std::unique_ptr{ 21 | new MultiheaderPropagator{FieldNameTraceID, FieldNameSpanID, 22 | FieldNameSampled, PrefixBaggage, false}}; 23 | } 24 | } // namespace lightstep 25 | -------------------------------------------------------------------------------- /test/recorder/in_memory_sync_transporter.cpp: -------------------------------------------------------------------------------- 1 | #include "test/recorder/in_memory_sync_transporter.h" 2 | 3 | namespace lightstep { 4 | //------------------------------------------------------------------------------ 5 | // Send 6 | //------------------------------------------------------------------------------ 7 | opentracing::expected InMemorySyncTransporter::Send( 8 | const google::protobuf::Message& request, 9 | google::protobuf::Message& response) { 10 | if (should_throw_) { 11 | throw std::runtime_error{"should_throw_ == true"}; 12 | } 13 | const auto& report = dynamic_cast(request); 14 | reports_.push_back(report); 15 | 16 | spans_.reserve(spans_.size() + report.spans_size()); 17 | for (auto& span : report.spans()) { 18 | spans_.push_back(span); 19 | } 20 | response.CopyFrom(*Transporter::MakeCollectorResponse()); 21 | if (should_disable_) { 22 | collector::Command command; 23 | command.set_disable(true); 24 | auto& report_response = dynamic_cast(response); 25 | *report_response.add_commands() = command; 26 | } 27 | return {}; 28 | } 29 | } // namespace lightstep 30 | -------------------------------------------------------------------------------- /src/tracer/legacy/BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "//bazel:lightstep_build_system.bzl", 3 | "lightstep_cc_library", 4 | "lightstep_package", 5 | ) 6 | 7 | lightstep_package() 8 | 9 | lightstep_cc_library( 10 | name = "lightstep_span_lib", 11 | private_hdrs = [ 12 | "legacy_span.h", 13 | ], 14 | srcs = [ 15 | "legacy_span.cpp", 16 | ], 17 | deps = [ 18 | "//src/common:logger_lib", 19 | "//src/common:utility_lib", 20 | "//src/common:random_lib", 21 | "//src/recorder:recorder_interface", 22 | "//src/tracer:lightstep_span_context_interface", 23 | "//src/tracer:utility_lib", 24 | "//src/tracer:tag_lib", 25 | ], 26 | ) 27 | 28 | lightstep_cc_library( 29 | name = "legacy_tracer_impl_lib", 30 | private_hdrs = [ 31 | "legacy_tracer_impl.h", 32 | ], 33 | srcs = [ 34 | "legacy_tracer_impl.cpp", 35 | ], 36 | deps = [ 37 | "//src/common:logger_lib", 38 | "//src/recorder:recorder_interface", 39 | ":lightstep_span_lib", 40 | "//src/tracer/propagation:propagation_lib", 41 | "//src/tracer:immutable_span_context_lib", 42 | ], 43 | ) 44 | 45 | -------------------------------------------------------------------------------- /cmake/Modules/LightStepTracerConfiguration.cmake: -------------------------------------------------------------------------------- 1 | set(PROTO_PATH "${CMAKE_SOURCE_DIR}/lightstep-tracer-configuration") 2 | 3 | set(TRACER_CONFIGURATION_PROTO ${PROTO_PATH}/tracer_configuration.proto) 4 | set(GENERATED_PROTOBUF_PATH ${CMAKE_BINARY_DIR}/generated/lightstep-tracer-configuration) 5 | file(MAKE_DIRECTORY ${GENERATED_PROTOBUF_PATH}) 6 | 7 | set(TRACER_CONFIGURATION_PB_CPP_FILE ${GENERATED_PROTOBUF_PATH}/tracer_configuration.pb.cc) 8 | set(TRACER_CONFIGURATION_PB_H_FILE ${GENERATED_PROTOBUF_PATH}/tracer_configuration.pb.h) 9 | 10 | add_custom_command( 11 | OUTPUT ${TRACER_CONFIGURATION_PB_CPP_FILE} 12 | ${TRACER_CONFIGURATION_PB_H_FILE} 13 | COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} 14 | ARGS "--proto_path=${PROTO_PATH}" 15 | "--cpp_out=${GENERATED_PROTOBUF_PATH}" 16 | ${TRACER_CONFIGURATION_PROTO} 17 | ) 18 | 19 | include_directories(SYSTEM ${GENERATED_PROTOBUF_PATH}) 20 | include_directories(SYSTEM ${GENERATED_PROTOBUF_PATH}/../) 21 | 22 | add_library(lightstep_tracer_configuration OBJECT ${TRACER_CONFIGURATION_PB_CPP_FILE}) 23 | 24 | if (BUILD_SHARED_LIBS) 25 | set_property(TARGET lightstep_tracer_configuration PROPERTY POSITION_INDEPENDENT_CODE ON) 26 | endif() 27 | -------------------------------------------------------------------------------- /test/network/no_dns_resolver_test.cpp: -------------------------------------------------------------------------------- 1 | #include "network/dns_resolver.h" 2 | 3 | #include "common/logger.h" 4 | #include "network/event_base.h" 5 | #include "test/mock_dns_resolution_callback.h" 6 | 7 | #include "3rd_party/catch2/catch.hpp" 8 | 9 | using namespace lightstep; 10 | 11 | TEST_CASE("NoDnsResolver") { 12 | Logger logger; 13 | EventBase event_base; 14 | DnsResolverOptions resolver_options; 15 | auto resolver = MakeDnsResolver(logger, event_base, resolver_options); 16 | MockDnsResolutionCallback callback{event_base}; 17 | 18 | SECTION("We can resolve raw ip addresses.") { 19 | resolver->Resolve("192.168.0.2", AF_INET, callback); 20 | REQUIRE(callback.ip_addresses() == 21 | std::vector{IpAddress{"192.168.0.2"}}); 22 | REQUIRE(callback.error_message().empty()); 23 | } 24 | 25 | SECTION("Resolving an ipv4 address as ipv6 fails.") { 26 | resolver->Resolve("192.168.0.2", AF_INET6, callback); 27 | REQUIRE(callback.ip_addresses().empty()); 28 | } 29 | 30 | SECTION("Resolving a non-ip address fails.") { 31 | resolver->Resolve("www.google.com", AF_INET, callback); 32 | REQUIRE(callback.ip_addresses().empty()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /test/recorder/stream_recorder/utility_test.cpp: -------------------------------------------------------------------------------- 1 | #include "recorder/stream_recorder/utility.h" 2 | 3 | #include "3rd_party/catch2/catch.hpp" 4 | using namespace lightstep; 5 | 6 | TEST_CASE("SeparateEndpoints") { 7 | std::vector hosts; 8 | std::vector> indexed_endpoints; 9 | 10 | SECTION("Endpoints with the same host are separated out.") { 11 | std::vector> endpoints = { 12 | {"abc", 123}, {"xyz", 456}, {"abc", 789}}; 13 | 14 | std::tie(hosts, indexed_endpoints) = SeparateEndpoints(endpoints); 15 | REQUIRE(hosts.size() == 2); 16 | REQUIRE(hosts[0] == std::string{"abc"}); 17 | REQUIRE(hosts[1] == std::string{"xyz"}); 18 | REQUIRE(indexed_endpoints == std::vector>{ 19 | {0, 123}, {1, 456}, {0, 789}}); 20 | } 21 | 22 | SECTION("Case is ignored when comparing hosts.") { 23 | std::vector> endpoints = {{"abc", 123}, 24 | {"ABC", 456}}; 25 | std::tie(hosts, indexed_endpoints) = SeparateEndpoints(endpoints); 26 | REQUIRE(hosts.size() == 1); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/echo_server/echo_server_handle.cpp: -------------------------------------------------------------------------------- 1 | #include "test/echo_server/echo_server_handle.h" 2 | 3 | #include 4 | 5 | #include "test/utility.h" 6 | 7 | namespace lightstep { 8 | //-------------------------------------------------------------------------------------------------- 9 | // constructor 10 | //-------------------------------------------------------------------------------------------------- 11 | EchoServerHandle::EchoServerHandle(uint16_t http_port, uint16_t tcp_port) 12 | : handle_{"test/echo_server/echo_server", 13 | {std::to_string(http_port), std::to_string(tcp_port)}}, 14 | http_connection_{"127.0.0.1", http_port} { 15 | if (!IsEventuallyTrue([http_port, tcp_port] { 16 | return CanConnect(http_port) && CanConnect(tcp_port); 17 | })) { 18 | std::cerr << "Failed to connect to echo server\n"; 19 | std::terminate(); 20 | } 21 | } 22 | 23 | //-------------------------------------------------------------------------------------------------- 24 | // data 25 | //-------------------------------------------------------------------------------------------------- 26 | std::string EchoServerHandle::data() { return http_connection_.Get("/data"); } 27 | } // namespace lightstep 28 | -------------------------------------------------------------------------------- /test/network/ip_address_test.cpp: -------------------------------------------------------------------------------- 1 | #include "network/ip_address.h" 2 | 3 | #include "3rd_party/catch2/catch.hpp" 4 | 5 | using namespace lightstep; 6 | 7 | TEST_CASE("IpAddress") { 8 | IpAddress addr1{"192.168.0.1"}, addr2{"192.168.1.1"}, 9 | addr3{"FE80:CD00:0000:03DE:1257:0000:211E:729C"}, 10 | addr4{"FE80:CD00:0000:0CDE:1257:0000:211E:729C"}; 11 | 12 | SECTION("Addresses can be converted to strings.") { 13 | REQUIRE(ToString(addr1) == "192.168.0.1"); 14 | REQUIRE(ToString(addr3) == "fe80:cd00:0:3de:1257:0:211e:729c"); 15 | } 16 | 17 | SECTION("Addresses can be compared.") { 18 | REQUIRE(addr1 == addr1); 19 | REQUIRE(addr1 != addr2); 20 | REQUIRE(addr1 != addr3); 21 | REQUIRE(addr3 == addr3); 22 | REQUIRE(addr3 != addr4); 23 | } 24 | 25 | SECTION("Addresses can be constructed from sockaddr.") { 26 | IpAddress addr5{addr1.addr()}, addr6{addr3.addr()}; 27 | REQUIRE(addr5 == addr1); 28 | REQUIRE(addr6 == addr3); 29 | } 30 | 31 | SECTION("The port can be set.") { 32 | addr1.set_port(8080); 33 | REQUIRE(addr1.ipv4_address().sin_port == htons(8080)); 34 | addr3.set_port(8080); 35 | REQUIRE(addr3.ipv6_address().sin6_port == htons(8080)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/tracer/propagation/propagator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "tracer/baggage_flat_map.h" 4 | #include "tracer/propagation/trace_context.h" 5 | 6 | #include 7 | 8 | #include 9 | 10 | namespace lightstep { 11 | using BaggageProtobufMap = google::protobuf::Map; 12 | 13 | class Propagator { 14 | public: 15 | virtual ~Propagator() noexcept = default; 16 | 17 | virtual opentracing::expected InjectSpanContext( 18 | const opentracing::TextMapWriter& carrier, 19 | const TraceContext& trace_context, opentracing::string_view trace_state, 20 | const BaggageProtobufMap& baggage) const = 0; 21 | 22 | virtual opentracing::expected InjectSpanContext( 23 | const opentracing::TextMapWriter& carrier, 24 | const TraceContext& trace_context, opentracing::string_view trace_state, 25 | const BaggageFlatMap& baggage) const = 0; 26 | 27 | virtual opentracing::expected ExtractSpanContext( 28 | const opentracing::TextMapReader& carrier, bool case_sensitive, 29 | TraceContext& trace_context, std::string& trace_state, 30 | BaggageProtobufMap& baggage) const = 0; 31 | }; 32 | } // namespace lightstep 33 | -------------------------------------------------------------------------------- /lightstep-tracer-common/third_party/googleapis/google/api/annotations.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package google.api; 18 | 19 | import "google/api/http.proto"; 20 | import "google/protobuf/descriptor.proto"; 21 | 22 | option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; 23 | option java_multiple_files = true; 24 | option java_outer_classname = "AnnotationsProto"; 25 | option java_package = "com.google.api"; 26 | option objc_class_prefix = "GAPI"; 27 | 28 | extend google.protobuf.MethodOptions { 29 | // See `HttpRule`. 30 | HttpRule http = 72295728; 31 | } 32 | -------------------------------------------------------------------------------- /test/common/logger_test.cpp: -------------------------------------------------------------------------------- 1 | #include "common/logger.h" 2 | 3 | #include "3rd_party/catch2/catch.hpp" 4 | using namespace lightstep; 5 | 6 | TEST_CASE("logger") { 7 | LogLevel logged_level = LogLevel::off; 8 | std::string logged_message; 9 | Logger logger{[&](LogLevel level, opentracing::string_view message) { 10 | logged_level = level; 11 | logged_message = message; 12 | }}; 13 | logger.set_level(LogLevel::warn); 14 | 15 | SECTION( 16 | "If log level is less than the logger's level, the message is ignored") { 17 | logger.Info("t"); 18 | CHECK(logged_message.empty()); 19 | } 20 | 21 | SECTION( 22 | "If log level is greater than or equal to the logger's message, the " 23 | "logger sink receive's the message") { 24 | logger.Warn("t1"); 25 | CHECK(logged_level == LogLevel::warn); 26 | CHECK(logged_message == "t1"); 27 | 28 | logger.Error("t2"); 29 | CHECK(logged_level == LogLevel::error); 30 | CHECK(logged_message == "t2"); 31 | } 32 | 33 | SECTION("Multiple arguments are concatenated together") { 34 | logger.Warn("a", "bc"); 35 | CHECK(logged_message == "abc"); 36 | 37 | logger.Warn("a", "bc", 123); 38 | CHECK(logged_message == "abc123"); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /benchmark/tracer_upload_bench/benchmark_report.cpp: -------------------------------------------------------------------------------- 1 | #include "benchmark_report.h" 2 | 3 | #include 4 | 5 | namespace lightstep { 6 | std::ostream& operator<<(std::ostream& out, const BenchmarkReport& report) { 7 | std::cout << "Approx Span size (bytes): " << report.approx_span_size << "\n"; 8 | std::cout << "Total spans: " << report.num_spans_generated << "\n"; 9 | std::cout << "Dropped spans: " << report.num_dropped_spans << "\n"; 10 | 11 | auto dropped_span_percent = 100.0 * 12 | static_cast(report.num_dropped_spans) / 13 | report.num_spans_generated; 14 | std::cout << "Dropped spans (%): " << dropped_span_percent << "\n"; 15 | auto num_spans_sent = report.num_spans_generated - report.num_dropped_spans; 16 | auto upload_rate = 17 | 1e6 * static_cast(num_spans_sent) / report.duration.count(); 18 | std::cout << "Upload rate (spans/sec): " << upload_rate << "\n"; 19 | auto upload_rate_bytes = 1e6 * static_cast(num_spans_sent) * 20 | report.approx_span_size / report.duration.count(); 21 | std::cout << "Approx upload (bytes/sec): " << upload_rate_bytes << "\n"; 22 | return out; 23 | } 24 | } // namespace lightstep 25 | -------------------------------------------------------------------------------- /example/tutorial/text_map_carrier.h: -------------------------------------------------------------------------------- 1 | #ifndef LIGHTSTEP_TEXT_MAP_CARRIER 2 | #define LIGHTSTEP_TEXT_MAP_CARRIER 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class TextMapCarrier : public opentracing::TextMapReader, 9 | public opentracing::TextMapWriter { 10 | public: 11 | TextMapCarrier(std::unordered_map& text_map) 12 | : text_map_(text_map) {} 13 | 14 | opentracing::expected Set( 15 | opentracing::string_view key, 16 | opentracing::string_view value) const override { 17 | text_map_[key] = value; 18 | return {}; 19 | } 20 | 21 | opentracing::expected ForeachKey( 22 | std::function(opentracing::string_view key, 23 | opentracing::string_view value)> 24 | f) const override { 25 | for (const auto& key_value : text_map_) { 26 | auto result = f(key_value.first, key_value.second); 27 | if (!result) { 28 | return result; 29 | } 30 | } 31 | return {}; 32 | } 33 | 34 | private: 35 | std::unordered_map& text_map_; 36 | }; 37 | 38 | #endif // LIGHTSTEP_TEXT_MAP_CARRIER 39 | -------------------------------------------------------------------------------- /cmake/Modules/FindCARES.cmake: -------------------------------------------------------------------------------- 1 | # - Find c-ares 2 | # Find the c-ares includes and library 3 | # This module defines 4 | # CARES_INCLUDE_DIR, where to find ares.h, etc. 5 | # CARES_LIBRARIES, the libraries needed to use c-ares. 6 | # CARES_FOUND, If false, do not try to use c-ares. 7 | # also defined, but not for general use are 8 | # CARES_LIBRARY, where to find the c-ares library. 9 | # Taken from https://github.com/curl/curl/blob/d1207c07d0cc3c7870e50865052bb59850917ec9/CMake/FindCARES.cmake 10 | 11 | find_path(CARES_INCLUDE_DIR ares.h 12 | /usr/local/include 13 | /usr/include 14 | ) 15 | 16 | set(CARES_NAMES ${CARES_NAMES} cares) 17 | find_library(CARES_LIBRARY 18 | NAMES ${CARES_NAMES} 19 | PATHS /usr/lib /usr/local/lib 20 | ) 21 | 22 | if(CARES_LIBRARY AND CARES_INCLUDE_DIR) 23 | set(CARES_LIBRARIES ${CARES_LIBRARY}) 24 | set(CARES_FOUND "YES") 25 | else() 26 | set(CARES_FOUND "NO") 27 | endif() 28 | 29 | 30 | if(CARES_FOUND) 31 | if(NOT CARES_FIND_QUIETLY) 32 | message(STATUS "Found c-ares: ${CARES_LIBRARIES}") 33 | endif() 34 | else() 35 | if(CARES_FIND_REQUIRED) 36 | message(FATAL_ERROR "Could not find c-ares library") 37 | endif() 38 | endif() 39 | 40 | mark_as_advanced( 41 | CARES_LIBRARY 42 | CARES_INCLUDE_DIR 43 | ) 44 | -------------------------------------------------------------------------------- /3rd_party/base64/include/lightstep/base64/base64.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace lightstep { 7 | class Base64 { 8 | public: 9 | /** 10 | * Base64 encode an input char buffer with a given length. 11 | * @param input char array to encode. 12 | * @param length of the input array. 13 | */ 14 | static std::string encode(const char* input, uint64_t length); 15 | 16 | /** 17 | * Base64 decode an input string. 18 | * @param input char array to decode. 19 | * @param length of the input array. 20 | * 21 | * Note, decoded string may contain '\0' at any position, it should be treated as a sequence of 22 | * bytes. 23 | */ 24 | static std::string decode(const char* input, size_t length); 25 | 26 | private: 27 | /** 28 | * Helper method for encoding. This is used to encode all of the characters from the input string. 29 | */ 30 | static void encodeBase(const uint8_t cur_char, uint64_t pos, uint8_t& next_c, std::string& ret); 31 | 32 | /** 33 | * Encode last characters. It appends '=' chars to the ret if input 34 | * string length is not divisible by 3. 35 | */ 36 | static void encodeLast(uint64_t pos, uint8_t last_char, std::string& ret); 37 | }; 38 | } // namespace lightstep 39 | -------------------------------------------------------------------------------- /src/recorder/report_builder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "lightstep-tracer-common/collector.pb.h" 8 | 9 | namespace lightstep { 10 | // ReportBuilder helps construct lightstep::collector::ReportRequest messages. 11 | // Not thread-safe, thread compatible. 12 | class ReportBuilder { 13 | public: 14 | ReportBuilder( 15 | const std::string& access_token, 16 | const std::unordered_map& tags); 17 | 18 | // AddSpan adds the span to the currently-building ReportRequest. 19 | void AddSpan(const collector::Span& span); 20 | 21 | // num_pending_spans() is the number of pending spans. 22 | size_t num_pending_spans() const { return pending_.spans_size(); } 23 | 24 | void set_pending_client_dropped_spans(uint64_t spans); 25 | 26 | // pending() returns a mutable object, appropriate for swapping with 27 | // another ReportRequest object. 28 | collector::ReportRequest& pending() { 29 | reset_next_ = true; 30 | return pending_; 31 | } 32 | 33 | private: 34 | bool reset_next_ = true; 35 | collector::ReportRequest preamble_; 36 | collector::ReportRequest pending_; 37 | }; 38 | } // namespace lightstep 39 | -------------------------------------------------------------------------------- /test/common/report_request_framing_test.cpp: -------------------------------------------------------------------------------- 1 | #include "common/report_request_framing.h" 2 | 3 | #include "lightstep-tracer-common/collector.pb.h" 4 | 5 | #include "3rd_party/catch2/catch.hpp" 6 | using namespace lightstep; 7 | 8 | TEST_CASE("ReportRequestFraming") { 9 | std::string header_serialization(ReportRequestSpansMaxHeaderSize, ' '); 10 | 11 | SECTION("We can successfully parse out serialized spans") { 12 | collector::ReportRequest report; 13 | collector::Span span; 14 | span.mutable_span_context()->set_trace_id(123); 15 | auto s = span.SerializeAsString(); 16 | auto header_size = WriteReportRequestSpansHeader( 17 | &header_serialization[0], header_serialization.size(), s.size()); 18 | s = header_serialization.substr(header_serialization.size() - header_size) + 19 | s; 20 | REQUIRE(report.ParseFromString(s)); 21 | REQUIRE(report.spans().size() == 1); 22 | REQUIRE(report.spans()[0].span_context().trace_id() == 123); 23 | } 24 | 25 | SECTION("We can serialize the largest header") { 26 | REQUIRE(WriteReportRequestSpansHeader( 27 | &header_serialization[0], header_serialization.size(), 28 | std::numeric_limits::max()) == 29 | header_serialization.size()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /test/recorder/legacy_in_memory_async_transporter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "lightstep-tracer-common/collector.pb.h" 9 | #include "lightstep/transporter.h" 10 | 11 | namespace lightstep { 12 | class LegacyInMemoryAsyncTransporter final : public LegacyAsyncTransporter { 13 | public: 14 | void Write(); 15 | 16 | void Fail(std::error_code error); 17 | 18 | const std::vector& reports() const { 19 | return reports_; 20 | } 21 | 22 | const std::vector& spans() const { return spans_; } 23 | 24 | void set_should_disable(bool value) { should_disable_ = value; } 25 | 26 | // LegacyAsyncTransporter 27 | void Send(const google::protobuf::Message& request, 28 | google::protobuf::Message& response, 29 | LegacyAsyncTransporter::Callback& callback) override; 30 | 31 | private: 32 | bool should_disable_ = false; 33 | const google::protobuf::Message* active_request_; 34 | google::protobuf::Message* active_response_; 35 | LegacyAsyncTransporter::Callback* active_callback_; 36 | std::vector reports_; 37 | std::vector spans_; 38 | }; 39 | } // namespace lightstep 40 | -------------------------------------------------------------------------------- /test/recorder/stream_recorder/stream_recorder_fork_test.cpp: -------------------------------------------------------------------------------- 1 | #include "recorder/stream_recorder/stream_recorder.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "test/mock_satellite/mock_satellite_handle.h" 7 | #include "test/ports.h" 8 | #include "test/utility.h" 9 | 10 | #include "3rd_party/catch2/catch.hpp" 11 | using namespace lightstep; 12 | 13 | TEST_CASE("StreamRecorder can be forked") { 14 | LightStepTracerOptions tracer_options; 15 | tracer_options.access_token = "abc123"; 16 | tracer_options.collector_plaintext = true; 17 | tracer_options.satellite_endpoints = { 18 | {"localhost", 19 | static_cast(PortAssignments::StreamRecorderForkTest)}}; 20 | tracer_options.use_stream_recorder = true; 21 | auto tracer = MakeLightStepTracer(std::move(tracer_options)); 22 | REQUIRE(tracer != nullptr); 23 | 24 | tracer->StartSpan("abc"); 25 | if (::fork() == 0) { 26 | tracer->StartSpan("xyz"); 27 | tracer->Close(); 28 | std::exit(0); 29 | } 30 | std::unique_ptr mock_satellite{new MockSatelliteHandle{ 31 | static_cast(PortAssignments::StreamRecorderForkTest)}}; 32 | tracer->Close(); 33 | REQUIRE( 34 | IsEventuallyTrue([&] { return mock_satellite->spans().size() == 2; })); 35 | } 36 | -------------------------------------------------------------------------------- /src/common/random_traverser.cpp: -------------------------------------------------------------------------------- 1 | #include "common/random_traverser.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "common/random.h" 7 | 8 | namespace lightstep { 9 | //-------------------------------------------------------------------------------------------------- 10 | // constructor 11 | //-------------------------------------------------------------------------------------------------- 12 | RandomTraverser::RandomTraverser(int n) : indexes_(n) { 13 | std::iota(indexes_.begin(), indexes_.end(), 0); 14 | } 15 | 16 | //-------------------------------------------------------------------------------------------------- 17 | // ForEachIndex 18 | //-------------------------------------------------------------------------------------------------- 19 | bool RandomTraverser::ForEachIndex(Callback callback) { 20 | if (indexes_.empty()) { 21 | return true; 22 | } 23 | auto n_minus_1 = static_cast(indexes_.size()) - 1; 24 | for (int i = 0; i < n_minus_1; ++i) { 25 | std::uniform_int_distribution distribution{i, n_minus_1}; 26 | std::swap(indexes_[i], indexes_[distribution(GetRandomNumberGenerator())]); 27 | if (!callback(indexes_[i])) { 28 | return false; 29 | } 30 | } 31 | return callback(indexes_.back()); 32 | } 33 | } // namespace lightstep 34 | -------------------------------------------------------------------------------- /test/common/random_traverser_test.cpp: -------------------------------------------------------------------------------- 1 | #include "common/random_traverser.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "3rd_party/catch2/catch.hpp" 7 | using namespace lightstep; 8 | 9 | TEST_CASE("RandomTraverser") { 10 | std::vector v(5, 0); 11 | RandomTraverser traverser{static_cast(v.size())}; 12 | 13 | SECTION( 14 | "RandomTraverser allows iteration over sequential indexes in random " 15 | "order.") { 16 | auto completed = traverser.ForEachIndex([&v](int i) { 17 | ++v[i]; 18 | return true; 19 | }); 20 | REQUIRE(completed); 21 | REQUIRE(std::all_of(v.begin(), v.end(), [](int x) { return x == 1; })); 22 | } 23 | 24 | SECTION("Iteration can be exited early by returning false.") { 25 | auto completed = traverser.ForEachIndex([&v](int i) { 26 | ++v[i]; 27 | return false; 28 | }); 29 | REQUIRE(!completed); 30 | std::sort(v.begin(), v.end()); 31 | REQUIRE(v == std::vector{0, 0, 0, 0, 1}); 32 | } 33 | 34 | SECTION("The callback is never called if the sequence is empty.") { 35 | traverser = RandomTraverser{0}; 36 | auto completed = traverser.ForEachIndex([](int /*i*/) { 37 | REQUIRE(false); 38 | return true; 39 | }); 40 | REQUIRE(completed); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test/common/direct_coded_output_stream_test.cpp: -------------------------------------------------------------------------------- 1 | #include "common/direct_coded_output_stream.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "3rd_party/catch2/catch.hpp" 10 | using namespace lightstep; 11 | 12 | TEST_CASE("DirectCodedOutputStream") { 13 | const size_t max_varint64_length = 10; 14 | std::array buffer; 15 | 16 | SECTION("Verify we can correctly serialize numbers") { 17 | for (int i = 0; i < 1000; ++i) { 18 | DirectCodedOutputStream stream{ 19 | reinterpret_cast(buffer.data())}; 20 | auto x = std::numeric_limits::max() - static_cast(i); 21 | stream.WriteBigVarint64(x); 22 | google::protobuf::io::ArrayInputStream zero_copy_stream{ 23 | static_cast(buffer.data()), 24 | static_cast( 25 | stream.data() - 26 | reinterpret_cast(buffer.data()))}; 27 | google::protobuf::io::CodedInputStream input_stream{&zero_copy_stream}; 28 | uint64_t x_prime; 29 | REQUIRE(input_stream.ReadVarint64(&x_prime)); 30 | REQUIRE(x == x_prime); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/tracer/propagation/text_map_carrier.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace lightstep { 8 | //------------------------------------------------------------------------------ 9 | // TextMapCarrier 10 | //------------------------------------------------------------------------------ 11 | struct TextMapCarrier : opentracing::TextMapReader, opentracing::TextMapWriter { 12 | explicit TextMapCarrier( 13 | std::unordered_map& text_map_); 14 | 15 | // opentracing::TextMapWriter 16 | opentracing::expected Set( 17 | opentracing::string_view key, 18 | opentracing::string_view value) const override; 19 | 20 | // opentracing::Text MapReader 21 | opentracing::expected LookupKey( 22 | opentracing::string_view key) const override; 23 | 24 | opentracing::expected ForeachKey( 25 | std::function(opentracing::string_view key, 26 | opentracing::string_view value)> 27 | f) const override; 28 | 29 | bool supports_lookup = false; 30 | mutable int foreach_key_call_count = 0; 31 | std::unordered_map& text_map; 32 | }; 33 | } // namespace lightstep 34 | -------------------------------------------------------------------------------- /include/lightstep/buffer_chain.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace lightstep { 6 | /** 7 | * BufferChain provides an interface to access a chained sequence of 8 | * contiguous memory buffers. 9 | */ 10 | class BufferChain { 11 | public: 12 | using FragmentCallback = bool (*)(void*, const void*, size_t); 13 | 14 | virtual ~BufferChain() = default; 15 | 16 | /** 17 | * @return the number of fragments in chain 18 | */ 19 | virtual size_t num_fragments() const noexcept = 0; 20 | 21 | /** 22 | * @return the total number of bytes in all fragments 23 | */ 24 | virtual size_t num_bytes() const noexcept = 0; 25 | 26 | /** 27 | * Iterate over each fragment in the buffer chain 28 | * @param callback the callback to call for each fragment 29 | * @param context a pointer to pass to the callback. 30 | */ 31 | virtual bool ForEachFragment(FragmentCallback callback, 32 | void* context) const = 0; 33 | 34 | /** 35 | * Copy out all the fragments into an area of contiguous memory 36 | * @param data the location to start copying 37 | * @param length the size of the buffer destination. Length must be at least 38 | * num_bytes. 39 | */ 40 | void CopyOut(char* data, size_t length) const noexcept; 41 | }; 42 | } // namespace lightstep 43 | -------------------------------------------------------------------------------- /test/recorder/in_memory_sync_transporter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "lightstep-tracer-common/collector.pb.h" 9 | #include "lightstep/transporter.h" 10 | 11 | namespace lightstep { 12 | class InMemorySyncTransporter : public SyncTransporter { 13 | public: 14 | opentracing::expected Send( 15 | const google::protobuf::Message& request, 16 | google::protobuf::Message& response) override; 17 | 18 | std::vector spans() const { 19 | std::lock_guard lock_guard{mutex_}; 20 | return spans_; 21 | } 22 | 23 | std::vector reports() const { 24 | std::lock_guard lock_guard{mutex_}; 25 | return reports_; 26 | } 27 | 28 | void set_should_throw(bool value) { 29 | std::lock_guard lock_guard{mutex_}; 30 | should_throw_ = value; 31 | } 32 | 33 | void set_should_disable(bool value) { 34 | std::lock_guard lock_guard{mutex_}; 35 | should_disable_ = value; 36 | } 37 | 38 | private: 39 | mutable std::mutex mutex_; 40 | bool should_throw_ = false; 41 | bool should_disable_ = false; 42 | std::vector reports_; 43 | std::vector spans_; 44 | }; 45 | } // namespace lightstep 46 | -------------------------------------------------------------------------------- /test/common/flat_map_test.cpp: -------------------------------------------------------------------------------- 1 | #include "common/flat_map.h" 2 | 3 | #include 4 | 5 | #include "3rd_party/catch2/catch.hpp" 6 | using namespace lightstep; 7 | 8 | TEST_CASE("FlatMap") { 9 | FlatMap map; 10 | REQUIRE(map.empty()); 11 | 12 | SECTION("We can insert_or_assign values into map") { 13 | map.insert_or_assign(3, 4); 14 | auto iter = map.find(3); 15 | REQUIRE(iter != map.end()); 16 | REQUIRE(iter->second == 4); 17 | } 18 | 19 | SECTION("We can replace a value already inserted") { 20 | map.insert_or_assign(3, 4); 21 | map.insert_or_assign(3, 7); 22 | auto iter = map.find(3); 23 | REQUIRE(iter != map.end()); 24 | REQUIRE(iter->second == 7); 25 | } 26 | 27 | SECTION("find returns the last iterator if the value isn't present") { 28 | REQUIRE(map.find(22) == map.end()); 29 | map.insert_or_assign(3, 4); 30 | REQUIRE(map.find(22) == map.end()); 31 | } 32 | 33 | SECTION("FlatMap keeps keys in sorted order") { 34 | for (int key : {3, 9, -1, 4, 5, 0, 10, 2}) { 35 | map.insert_or_assign(std::move(key), 33); 36 | auto comp = [](const std::pair& lhs, 37 | const std::pair& rhs) { 38 | return lhs.first < rhs.first; 39 | }; 40 | REQUIRE(std::is_sorted(map.begin(), map.end(), comp)); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/common/fork_id_test.cpp: -------------------------------------------------------------------------------- 1 | // Verifies that IDs don't clash after forking the process. 2 | // 3 | // See https://github.com/opentracing-contrib/nginx-opentracing/issues/52 4 | #include "common/random.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | using namespace lightstep; 14 | 15 | static uint64_t* child_id; 16 | 17 | int main() { 18 | GenerateId(); 19 | 20 | // Set up shared memory to communicate between parent and child processes. 21 | // 22 | // See https://stackoverflow.com/a/13274800/4447365 23 | child_id = static_cast(mmap(nullptr, sizeof(*child_id), 24 | PROT_READ | PROT_WRITE, 25 | MAP_SHARED | MAP_ANONYMOUS, -1, 0)); 26 | *child_id = 0; 27 | if (fork() == 0) { 28 | *child_id = GenerateId(); 29 | exit(EXIT_SUCCESS); 30 | } else { 31 | wait(nullptr); 32 | auto parent_id = GenerateId(); 33 | auto child_id_copy = *child_id; 34 | munmap(static_cast(child_id), sizeof(*child_id)); 35 | if (parent_id == child_id_copy) { 36 | std::cerr << "Child and parent ids are the same value " << parent_id 37 | << "\n"; 38 | return -1; 39 | } 40 | } 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /test/mock_satellite/mock_satellite_handle.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "test/child_process_handle.h" 6 | #include "test/http_connection.h" 7 | #include "test/mock_satellite/mock_satellite.pb.h" 8 | 9 | namespace lightstep { 10 | /** 11 | * Manages a server that acts like a satellite. 12 | */ 13 | class MockSatelliteHandle { 14 | public: 15 | explicit MockSatelliteHandle(uint16_t port); 16 | 17 | /** 18 | * @return the spans recorded by the satellite. 19 | */ 20 | std::vector spans(); 21 | 22 | /** 23 | * @return the reports recorded by the satellite. 24 | */ 25 | std::vector reports(); 26 | 27 | /** 28 | * Forces the mock satellite to return an HTTP error code for the next report 29 | * request. 30 | */ 31 | void SetRequestError(); 32 | 33 | /** 34 | * Forces the mock satellite to timeout for the next report request. 35 | */ 36 | void SetRequestTimeout(); 37 | 38 | /** 39 | * Forces the mock satellite to prematurely close the next report request. 40 | */ 41 | void SetRequestPrematureClose(); 42 | 43 | /** 44 | * Instructs the satellite to read requests out more slowly 45 | */ 46 | void SetThrottleReports(); 47 | 48 | private: 49 | ChildProcessHandle handle_; 50 | HttpConnection connection_; 51 | }; 52 | } // namespace lightstep 53 | -------------------------------------------------------------------------------- /lightstep-tracer-common/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_proto//proto:defs.bzl", "proto_library") 2 | 3 | proto_library( 4 | name = "collector_proto", 5 | srcs = ["collector.proto"], 6 | deps = [ 7 | "@com_google_googleapis//google/api:annotations_proto", 8 | "@com_google_protobuf//:descriptor_proto", 9 | "@com_google_protobuf//:timestamp_proto", 10 | ], 11 | visibility = ["//visibility:public"], 12 | ) 13 | 14 | cc_proto_library( 15 | name = "collector_proto_cc", 16 | deps = [":collector_proto"], 17 | visibility = ["//visibility:public"], 18 | ) 19 | 20 | proto_library( 21 | name = "lightstep_carrier_proto", 22 | srcs = ["lightstep_carrier.proto"], 23 | visibility = ["//visibility:public"], 24 | ) 25 | 26 | cc_proto_library( 27 | name = "lightstep_carrier_proto_cc", 28 | deps = [":lightstep_carrier_proto"], 29 | visibility = ["//visibility:public"], 30 | ) 31 | 32 | load("@com_github_grpc_grpc//bazel:cc_grpc_library.bzl", "cc_grpc_library") 33 | 34 | cc_grpc_library( 35 | name = "collector_proto_grpc", 36 | srcs = [ 37 | ":collector_proto", 38 | ], 39 | deps = [ 40 | ":collector_proto_cc", 41 | "@com_github_grpc_grpc//:grpc++", 42 | "@com_github_grpc_grpc//:grpc++_reflection", 43 | ], 44 | grpc_only = True, 45 | visibility = ["//visibility:public"], 46 | ) 47 | -------------------------------------------------------------------------------- /ci/release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | apt-get update 5 | apt-get install --no-install-recommends --no-install-suggests -y \ 6 | wget \ 7 | unzip \ 8 | python python-pip 9 | pip install twine 10 | 11 | # Install ghr 12 | cd / 13 | wget https://github.com/tcnksm/ghr/releases/download/v0.5.4/ghr_v0.5.4_linux_amd64.zip 14 | unzip ghr_v0.5.4_linux_amd64.zip 15 | 16 | # Create packaged plugins 17 | gzip -c /plugin/liblightstep_tracer_plugin.so > /linux-amd64-liblightstep_tracer_plugin.so.gz 18 | 19 | # Create release 20 | cd "${SRC_DIR}" 21 | VERSION_TAG="`git describe --abbrev=0 --tags`" 22 | 23 | RELEASE_TITLE="${VERSION_TAG/v/Release }" 24 | # No way to set title see https://github.com/tcnksm/ghr/issues/77 25 | 26 | echo "/ghr -t \ 27 | -u $CIRCLE_PROJECT_USERNAME \ 28 | -r $CIRCLE_PROJECT_REPONAME \ 29 | -replace \ 30 | "${VERSION_TAG}" \ 31 | /linux-amd64-liblightstep_tracer_plugin.so.gz" 32 | /ghr -t $GITHUB_TOKEN \ 33 | -u $CIRCLE_PROJECT_USERNAME \ 34 | -r $CIRCLE_PROJECT_REPONAME \ 35 | -replace \ 36 | "${VERSION_TAG}" \ 37 | /linux-amd64-liblightstep_tracer_plugin.so.gz 38 | 39 | # Upload the wheel to pypi 40 | echo -e "[pypi]" >> ~/.pypirc 41 | echo -e "username = $PYPI_USER" >> ~/.pypirc 42 | echo -e "password = $PYPI_PASSWORD" >> ~/.pypirc 43 | twine upload /plugin/*.whl 44 | -------------------------------------------------------------------------------- /src/common/fragment_array_input_stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "common/fragment_input_stream.h" 7 | 8 | namespace lightstep { 9 | /** 10 | * A non-owning stream of fragments. 11 | */ 12 | class FragmentArrayInputStream final : public FragmentInputStream { 13 | public: 14 | FragmentArrayInputStream() noexcept = default; 15 | 16 | explicit FragmentArrayInputStream(std::initializer_list fragments); 17 | 18 | FragmentArrayInputStream& operator=( 19 | std::initializer_list fragments); 20 | 21 | /** 22 | * Reserve memory for fragments. 23 | * @param size the number of fragments to reserve memory for. 24 | */ 25 | void Reserve(size_t size) { fragments_.reserve(size); } 26 | 27 | /** 28 | * Add a fragment to the stream. 29 | * @param fragment the fragment to add. 30 | */ 31 | void Add(Fragment fragment) { fragments_.emplace_back(fragment); } 32 | 33 | // FragmentInputStream 34 | int num_fragments() const noexcept override; 35 | 36 | bool ForEachFragment(Callback callback) const noexcept override; 37 | 38 | void Clear() noexcept override; 39 | 40 | void Seek(int fragment_index, int position) noexcept override; 41 | 42 | private: 43 | std::vector fragments_; 44 | 45 | int fragment_index_{0}; 46 | int position_{0}; 47 | }; 48 | } // namespace lightstep 49 | -------------------------------------------------------------------------------- /src/common/platform/error.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef _WIN32 4 | #define NOMINMAX 5 | #define WIN32_LEAN_AND_MEAN 6 | #include 7 | #endif 8 | 9 | #include 10 | 11 | namespace lightstep { 12 | #ifdef _WIN32 13 | using ErrorCode = DWORD; 14 | #else 15 | using ErrorCode = int; 16 | #endif 17 | 18 | /** 19 | * Many windows functions don't use errno. This function provides a platform 20 | * indpendent way of getting the last error code. 21 | * @return the last error code set from a system call 22 | */ 23 | ErrorCode GetLastErrorCode() noexcept; 24 | 25 | /** 26 | * Convert an error code to a human readable message. 27 | * @param error_code the error code to convert 28 | * @return the message for the given error code 29 | */ 30 | std::string GetErrorCodeMessage(ErrorCode error_code); 31 | 32 | /** 33 | * Determine if an error code represents an "operation would block" error. 34 | * @param error_code the error code to check 35 | * @return true if the given error code is for blocking 36 | */ 37 | bool IsBlockingErrorCode(ErrorCode error_code) noexcept; 38 | 39 | /** 40 | * Determine if an error code represents an "operation in progress" error. 41 | * @param error_code the error code to check 42 | * @return true if the given error code is for an in progress operation 43 | */ 44 | bool IsInProgressErrorCode(ErrorCode error_code) noexcept; 45 | } // namespace lightstep 46 | -------------------------------------------------------------------------------- /test/common/circular_buffer_range_test.cpp: -------------------------------------------------------------------------------- 1 | #include "common/circular_buffer_range.h" 2 | 3 | #include 4 | 5 | #include "3rd_party/catch2/catch.hpp" 6 | using namespace lightstep; 7 | 8 | TEST_CASE("CircularBufferRange") { 9 | int array1[] = {1, 2, 3, 4}; 10 | int array2[] = {5, 6, 7}; 11 | CircularBufferRange range{std::begin(array1), std::end(array1), 12 | std::begin(array2), std::end(array2)}; 13 | 14 | SECTION("We can iterate over elements of a CircularBufferRange") { 15 | int x = 0; 16 | range.ForEach([&](int y) { 17 | REQUIRE(++x == y); 18 | return true; 19 | }); 20 | REQUIRE(x == 7); 21 | } 22 | 23 | SECTION("We can bail out of iteration over a CircularBufferRange") { 24 | int x = 0; 25 | range.ForEach([&](int y) { 26 | REQUIRE(++x == y); 27 | return false; 28 | }); 29 | REQUIRE(x == 1); 30 | 31 | x = 0; 32 | range.ForEach([&](int y) { 33 | REQUIRE(++x == y); 34 | return y != 5; 35 | }); 36 | REQUIRE(x == 5); 37 | } 38 | 39 | SECTION( 40 | "We can implicitly convert a non-const CircularBufferRange to a const " 41 | "one") { 42 | CircularBufferRange range2{range}; 43 | int x = 0; 44 | range2.ForEach([&](int y) { 45 | REQUIRE(++x == y); 46 | return true; 47 | }); 48 | REQUIRE(x == 7); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /bazel/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | load("@python_pip_deps//:requirements.bzl", "requirement") 4 | 5 | config_setting( 6 | name = "asan_build", 7 | values = {"define": "LIGHTSTEP_CONFIG_ASAN=1"}, 8 | ) 9 | 10 | config_setting( 11 | name = "tsan_build", 12 | values = {"define": "LIGHTSTEP_CONFIG_TSAN=1"}, 13 | ) 14 | 15 | config_setting( 16 | name = "portable_glibc_build", 17 | values = {"define": "LIGHTSTEP_PORTABLE_GLIBC=1"}, 18 | ) 19 | 20 | # Uses method described in this stackoverflow post 21 | # https://stackoverflow.com/a/5977518/4447365 22 | # to force linking to older glibc symbols 23 | cc_library( 24 | name = "glibc_version_lib", 25 | srcs = [ 26 | "glibc_version.cpp", 27 | ], 28 | linkopts = [ 29 | "-lrt", 30 | "-Wl,--wrap=memcpy", 31 | "-Wl,--wrap=clock_gettime", 32 | # Note grpc already uses this wrapping technique with memcpy, so we add this flag to prevent 33 | # a multiple definition error 34 | "-Wl,--allow-multiple-definition", 35 | ], 36 | ) 37 | 38 | py_binary( 39 | name = "run_gprof2dot", 40 | srcs = [ 41 | "run_gprof2dot.py", 42 | ], 43 | deps = [ 44 | requirement("gprof2dot"), 45 | ], 46 | ) 47 | 48 | sh_binary( 49 | name = "profile_benchmark", 50 | srcs = [ 51 | "profile_benchmark.sh", 52 | ], 53 | ) 54 | -------------------------------------------------------------------------------- /benchmark/tracer_upload_bench/main.cpp: -------------------------------------------------------------------------------- 1 | #include "lightstep/tracer.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "benchmark_report.h" 8 | #include "span.h" 9 | #include "utility.h" 10 | using namespace lightstep; 11 | 12 | int main(int argc, char* argv[]) try { 13 | if (argc != 2) { 14 | std::cout << "Usage: span-upload-bench \n"; 15 | return 1; 16 | } 17 | auto config = ParseConfiguration(argv[1]); 18 | std::shared_ptr tracer; 19 | SpanDropCounter* span_drop_counter; 20 | std::tie(tracer, span_drop_counter) = MakeTracer(config); 21 | std::this_thread::sleep_for(std::chrono::milliseconds{ 22 | static_cast(1000 * config.startup_delay())}); 23 | auto t1 = std::chrono::steady_clock::now(); 24 | GenerateSpans(*tracer, config); 25 | auto t2 = std::chrono::steady_clock::now(); 26 | BenchmarkReport report; 27 | report.num_spans_generated = 28 | config.num_spans_per_thread() * config.num_threads(); 29 | report.num_dropped_spans = span_drop_counter->num_dropped_spans(); 30 | report.duration = 31 | std::chrono::duration_cast(t2 - t1); 32 | report.approx_span_size = static_cast(ComputeSpanSize(config)); 33 | std::cout << report; 34 | return 0; 35 | } catch (const std::exception& e) { 36 | std::cerr << e.what() << "\n"; 37 | return -1; 38 | } 39 | -------------------------------------------------------------------------------- /include/lightstep/BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "//bazel:lightstep_build_system.bzl", 3 | "lightstep_cc_library", 4 | "lightstep_package", 5 | ) 6 | 7 | lightstep_package() 8 | 9 | lightstep_cc_library( 10 | name = "binary_carrier_interface", 11 | hdrs = [ 12 | "binary_carrier.h", 13 | ], 14 | deps = [ 15 | "//lightstep-tracer-common:lightstep_carrier_proto_cc", 16 | ], 17 | external_deps = [ 18 | "@io_opentracing_cpp//:opentracing", 19 | ], 20 | ) 21 | 22 | lightstep_cc_library( 23 | name = "buffer_chain_interface", 24 | hdrs = [ 25 | "buffer_chain.h", 26 | ], 27 | ) 28 | 29 | lightstep_cc_library( 30 | name = "transporter_interface", 31 | hdrs = [ 32 | "transporter.h", 33 | ], 34 | external_deps = [ 35 | ":buffer_chain_interface", 36 | "@com_google_protobuf//:protobuf", 37 | "@io_opentracing_cpp//:opentracing", 38 | ], 39 | ) 40 | 41 | lightstep_cc_library( 42 | name = "metrics_observer_interface", 43 | hdrs = [ 44 | "metrics_observer.h", 45 | ], 46 | ) 47 | 48 | lightstep_cc_library( 49 | name = "tracer_interface", 50 | hdrs = [ 51 | "tracer.h", 52 | ], 53 | deps = [ 54 | ":transporter_interface", 55 | ":metrics_observer_interface", 56 | ], 57 | external_deps = [ 58 | "@io_opentracing_cpp//:opentracing", 59 | ], 60 | ) 61 | -------------------------------------------------------------------------------- /src/recorder/serialization/BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "//bazel:lightstep_build_system.bzl", 3 | "lightstep_cc_library", 4 | "lightstep_package", 5 | ) 6 | 7 | lightstep_package() 8 | 9 | lightstep_cc_library( 10 | name = "report_request_lib", 11 | private_hdrs = [ 12 | "report_request.h", 13 | ], 14 | srcs = [ 15 | "report_request.cpp", 16 | ], 17 | deps = [ 18 | "//src/common:buffer_chain_lib", 19 | "//src/common:chained_stream_lib", 20 | ":embedded_metrics_message_lib", 21 | ], 22 | ) 23 | 24 | lightstep_cc_library( 25 | name = "report_request_header_lib", 26 | private_hdrs = [ 27 | "report_request_header.h", 28 | ], 29 | srcs = [ 30 | "report_request_header.cpp", 31 | ], 32 | deps = [ 33 | "//include/lightstep:tracer_interface", 34 | "//lightstep-tracer-common:collector_proto_cc", 35 | "//src/common:protobuf_lib", 36 | "//src/common:utility_lib", 37 | ":embedded_metrics_message_lib", 38 | ], 39 | ) 40 | 41 | lightstep_cc_library( 42 | name = "embedded_metrics_message_lib", 43 | private_hdrs = [ 44 | "embedded_metrics_message.h", 45 | ], 46 | srcs = [ 47 | "embedded_metrics_message.cpp", 48 | ], 49 | deps = [ 50 | "//lightstep-tracer-common:collector_proto_cc", 51 | "//src/common:protobuf_lib", 52 | ], 53 | ) 54 | -------------------------------------------------------------------------------- /src/recorder/serialization/report_request_header.cpp: -------------------------------------------------------------------------------- 1 | #include "recorder/serialization/report_request_header.h" 2 | 3 | #include "common/protobuf.h" 4 | #include "common/utility.h" 5 | #include "lightstep-tracer-common/collector.pb.h" 6 | 7 | #include 8 | #include 9 | 10 | namespace lightstep { 11 | std::string WriteReportRequestHeader( 12 | const LightStepTracerOptions& tracer_options, uint64_t reporter_id) { 13 | collector::Reporter reporter; 14 | reporter.set_reporter_id(reporter_id); 15 | reporter.mutable_tags()->Reserve( 16 | static_cast(tracer_options.tags.size())); 17 | for (const auto& tag : tracer_options.tags) { 18 | *reporter.mutable_tags()->Add() = ToKeyValue(tag.first, tag.second); 19 | } 20 | 21 | collector::Auth auth; 22 | auth.set_access_token(tracer_options.access_token); 23 | 24 | std::ostringstream oss; 25 | { 26 | google::protobuf::io::OstreamOutputStream zero_copy_stream{&oss}; 27 | google::protobuf::io::CodedOutputStream coded_stream{&zero_copy_stream}; 28 | 29 | WriteEmbeddedMessage( 30 | coded_stream, collector::ReportRequest::kReporterFieldNumber, reporter); 31 | WriteEmbeddedMessage(coded_stream, 32 | collector::ReportRequest::kAuthFieldNumber, auth); 33 | } 34 | 35 | return oss.str(); 36 | } 37 | } // namespace lightstep 38 | -------------------------------------------------------------------------------- /test/recorder/fork_aware_recorder_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "recorder/fork_aware_recorder.h" 4 | 5 | #include "3rd_party/catch2/catch.hpp" 6 | 7 | using namespace lightstep; 8 | 9 | class DummyRecorder final : public ForkAwareRecorder { 10 | public: 11 | void RecordSpan(const collector::Span& /*span*/) noexcept override {} 12 | }; 13 | 14 | TEST_CASE("ForkAwareRecorder") { 15 | REQUIRE(ForkAwareRecorder::GetActiveRecordersForTesting().empty()); 16 | 17 | SECTION("Active recorders are tracked in a global variable.") { 18 | std::unique_ptr recorder1{new DummyRecorder{}}; 19 | REQUIRE(ForkAwareRecorder::GetActiveRecordersForTesting().size() == 1); 20 | recorder1.reset(nullptr); 21 | REQUIRE(ForkAwareRecorder::GetActiveRecordersForTesting().empty()); 22 | } 23 | 24 | SECTION( 25 | "The active recorder list is properly updated when there are more than 1 " 26 | "recorders.") { 27 | std::unique_ptr recorder1{new DummyRecorder{}}; 28 | std::unique_ptr recorder2{new DummyRecorder{}}; 29 | std::unique_ptr recorder3{new DummyRecorder{}}; 30 | recorder2.reset(nullptr); 31 | REQUIRE(ForkAwareRecorder::GetActiveRecordersForTesting() == 32 | std::vector{recorder3.get(), 33 | recorder1.get()}); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /3rd_party/catch2/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /test/mock_satellite/mock_satellite_query.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "test/http_connection.h" 6 | #include "test/mock_satellite/mock_satellite.pb.h" 7 | 8 | #include 9 | 10 | DEFINE_string(host, "127.0.0.1", "the host of the mock satellite"); 11 | DEFINE_int32(port, 0, "the port of the mock satellite"); 12 | 13 | static void QueryNumSpans(lightstep::HttpConnection& connection) { 14 | lightstep::mock_satellite::Spans spans; 15 | connection.Get("/spans", spans); 16 | std::cout << spans.spans().size(); 17 | } 18 | 19 | int main(int argc, char* argv[]) try { 20 | gflags::ParseCommandLineFlags(&argc, &argv, true); 21 | if (FLAGS_port <= 0 || FLAGS_port > std::numeric_limits::max()) { 22 | std::cerr << "must provide a valid port for the mock satellite\n"; 23 | std::abort(); 24 | } 25 | if (argc != 2) { 26 | std::cerr << "no command provided\n"; 27 | std::abort(); 28 | } 29 | std::string command{argv[1]}; 30 | lightstep::HttpConnection connection{FLAGS_host.c_str(), 31 | static_cast(FLAGS_port)}; 32 | if (command == "num_spans") { 33 | QueryNumSpans(connection); 34 | return 0; 35 | } 36 | std::cerr << "Invalid command: " << command << "\n"; 37 | std::abort(); 38 | } catch (const std::exception& e) { 39 | std::cerr << e.what() << "\n"; 40 | std::abort(); 41 | } 42 | -------------------------------------------------------------------------------- /src/common/fragment_input_stream.cpp: -------------------------------------------------------------------------------- 1 | #include "common/fragment_input_stream.h" 2 | 3 | #include 4 | 5 | namespace lightstep { 6 | //-------------------------------------------------------------------------------------------------- 7 | // MakeFragment 8 | //-------------------------------------------------------------------------------------------------- 9 | Fragment MakeFragment(const char* s) noexcept { 10 | return {static_cast(const_cast(s)), 11 | static_cast(std::strlen(s))}; 12 | } 13 | 14 | //-------------------------------------------------------------------------------------------------- 15 | // Consume 16 | //-------------------------------------------------------------------------------------------------- 17 | bool Consume(std::initializer_list fragment_input_streams, 18 | int n) noexcept { 19 | for (auto fragment_input_stream : fragment_input_streams) { 20 | int fragment_index = 0; 21 | auto f = [&n, &fragment_index](void* /*data*/, int size) { 22 | if (n < size) { 23 | return false; 24 | } 25 | ++fragment_index; 26 | n -= size; 27 | return true; 28 | }; 29 | if (!fragment_input_stream->ForEachFragment(f)) { 30 | fragment_input_stream->Seek(fragment_index, n); 31 | return false; 32 | } 33 | fragment_input_stream->Clear(); 34 | } 35 | return true; 36 | } 37 | } // namespace lightstep 38 | -------------------------------------------------------------------------------- /src/tracer/lightstep_tracer_factory.cpp: -------------------------------------------------------------------------------- 1 | #include "tracer/lightstep_tracer_factory.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include "lightstep-tracer-configuration/tracer_configuration.pb.h" 9 | 10 | #include "tracer/json_options.h" 11 | 12 | namespace lightstep { 13 | //-------------------------------------------------------------------------------------------------- 14 | // MakeTracer 15 | //-------------------------------------------------------------------------------------------------- 16 | opentracing::expected> 17 | LightStepTracerFactory::MakeTracer(const char* configuration, 18 | std::string& error_message) const 19 | noexcept try { 20 | auto options_maybe = MakeTracerOptions(configuration, error_message); 21 | if (!options_maybe) { 22 | return opentracing::make_unexpected(options_maybe.error()); 23 | } 24 | auto result = std::shared_ptr{ 25 | MakeLightStepTracer(std::move(*options_maybe))}; 26 | if (result == nullptr) { 27 | return opentracing::make_unexpected( 28 | opentracing::invalid_configuration_error); 29 | } 30 | return result; 31 | } catch (const std::bad_alloc&) { 32 | return opentracing::make_unexpected( 33 | std::make_error_code(std::errc::not_enough_memory)); 34 | } 35 | } // namespace lightstep 36 | -------------------------------------------------------------------------------- /src/network/ares_dns_resolver/ares_dns_resolver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "common/noncopyable.h" 6 | #include "network/ares_dns_resolver/ares_library_handle.h" 7 | #include "network/dns_resolver.h" 8 | #include "network/event.h" 9 | #include "network/timer_event.h" 10 | 11 | struct ares_channeldata; 12 | 13 | namespace lightstep { 14 | /** 15 | * A DnsResolver using the c-ares library. 16 | */ 17 | class AresDnsResolver final : public DnsResolver, private Noncopyable { 18 | public: 19 | AresDnsResolver(Logger& logger, EventBase& event_base, 20 | const DnsResolverOptions& resolver_options); 21 | 22 | ~AresDnsResolver() noexcept override; 23 | 24 | // DnsResolver 25 | void Resolve(const char* name, int family, 26 | DnsResolutionCallback& callback) noexcept override; 27 | 28 | private: 29 | std::shared_ptr ares_library_handle_{ 30 | AresLibraryHandle::Instance}; 31 | Logger& logger_; 32 | EventBase& event_base_; 33 | ares_channeldata* channel_; 34 | 35 | std::unordered_map socket_events_; 36 | TimerEvent timer_; 37 | 38 | void OnSocketStateChange(FileDescriptor file_descriptor, int read, 39 | int write) noexcept; 40 | 41 | void OnEvent(FileDescriptor file_descriptor, short what) noexcept; 42 | 43 | void OnTimeout() noexcept; 44 | 45 | void UpdateTimer(); 46 | }; 47 | } // namespace lightstep 48 | -------------------------------------------------------------------------------- /src/network/timer_event.cpp: -------------------------------------------------------------------------------- 1 | #include "network/timer_event.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "common/utility.h" 7 | 8 | #include 9 | 10 | namespace lightstep { 11 | //-------------------------------------------------------------------------------------------------- 12 | // constructor 13 | //-------------------------------------------------------------------------------------------------- 14 | TimerEvent::TimerEvent(const EventBase& event_base, 15 | std::chrono::microseconds interval, 16 | Event::Callback callback, void* context) 17 | : event_{event_base, -1, EV_PERSIST, callback, context}, 18 | tv_{ToTimeval(interval)} { 19 | event_.Add(&tv_); 20 | } 21 | 22 | TimerEvent::TimerEvent(const EventBase& event_base, Event::Callback callback, 23 | void* context) 24 | : event_{event_base, -1, EV_PERSIST, callback, context} {} 25 | 26 | //-------------------------------------------------------------------------------------------------- 27 | // Reset 28 | //-------------------------------------------------------------------------------------------------- 29 | void TimerEvent::Reset() { 30 | event_.Remove(); 31 | event_.Add(&tv_); 32 | } 33 | 34 | void TimerEvent::Reset(const timeval* tv) { 35 | event_.Remove(); 36 | if (tv == nullptr) { 37 | return; 38 | } 39 | tv_ = *tv; 40 | event_.Add(&tv_); 41 | } 42 | } // namespace lightstep 43 | -------------------------------------------------------------------------------- /src/tracer/propagation/baggage_propagator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "tracer/propagation/propagator.h" 4 | 5 | namespace lightstep { 6 | class BaggagePropagator final : public Propagator { 7 | public: 8 | explicit BaggagePropagator(opentracing::string_view baggage_prefix) noexcept; 9 | 10 | // Propagator 11 | opentracing::expected InjectSpanContext( 12 | const opentracing::TextMapWriter& carrier, 13 | const TraceContext& trace_context, opentracing::string_view trace_state, 14 | const BaggageProtobufMap& baggage) const override; 15 | 16 | opentracing::expected InjectSpanContext( 17 | const opentracing::TextMapWriter& carrier, 18 | const TraceContext& trace_context, opentracing::string_view trace_state, 19 | const BaggageFlatMap& baggage) const override; 20 | 21 | opentracing::expected ExtractSpanContext( 22 | const opentracing::TextMapReader& /*carrier*/, bool /*case_sensitive*/, 23 | TraceContext& /*trace_context*/, std::string& /*trace_state*/, 24 | BaggageProtobufMap& /*baggage*/) const override { 25 | // Do nothing: baggage is extracted in the other propagators 26 | return false; 27 | } 28 | 29 | private: 30 | opentracing::string_view baggage_prefix_; 31 | 32 | template 33 | opentracing::expected InjectSpanContextImpl( 34 | const opentracing::TextMapWriter& carrier, 35 | const BaggageMap& baggage) const; 36 | }; 37 | } // namespace lightstep 38 | -------------------------------------------------------------------------------- /test/number_simulation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "common/chained_stream.h" 10 | #include "common/circular_buffer.h" 11 | #include "recorder/stream_recorder/connection_stream.h" 12 | 13 | #include 14 | 15 | namespace lightstep { 16 | /** 17 | * Randomly writes binary numbers into a given circular buffer. 18 | * @param buffer the buffer to write numbers into. 19 | * @param numbers outputs the numbers written. 20 | * @param num_threads the number of threads to write numbers on. 21 | * @param n the number of numbers to write. 22 | */ 23 | void RunBinaryNumberProducer(CircularBuffer& buffer, 24 | std::vector& numbers, size_t num_threads, 25 | size_t n); 26 | 27 | /** 28 | * Reads numbers out of the given ChunkCircularBuffer through the given 29 | * ConnectionStreams. 30 | * @param span_stream the SpanStream connected the ChunkCircularBuffer. 31 | * @param connection_streams the ConnectionStreams to read numbers out of. 32 | * @param exit indicates that the producer has finished. 33 | * @param numbers outputs the numbers read. 34 | */ 35 | void RunBinaryNumberConnectionConsumer( 36 | SpanStream& span_stream, std::vector& connection_streams, 37 | std::atomic& exit, std::vector& numbers); 38 | } // namespace lightstep 39 | -------------------------------------------------------------------------------- /src/recorder/metrics_tracker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace lightstep { 8 | /** 9 | * Manages the metrics associated with a StreamRecorder. 10 | */ 11 | class MetricsTracker { 12 | public: 13 | explicit MetricsTracker(MetricsObserver& metrics_observer) noexcept; 14 | 15 | /** 16 | * Record dropped spans. 17 | * @param num_spans the number of spans dropped. 18 | */ 19 | inline void OnSpansDropped(int num_spans) noexcept { 20 | metrics_observer_.OnSpansDropped(num_spans); 21 | num_dropped_spans_ += num_spans; 22 | } 23 | 24 | /** 25 | * Record spans sent. 26 | * @param num_spans the number of spans sent. 27 | */ 28 | void OnSpansSent(int num_spans) noexcept; 29 | 30 | /** 31 | * Record flushes. 32 | */ 33 | void OnFlush() noexcept; 34 | 35 | /** 36 | * Return then clear the dropped span counter. 37 | * @return the dropped span count. 38 | */ 39 | int ConsumeDroppedSpans() noexcept; 40 | 41 | /** 42 | * Add spans back to the dropped span counter. 43 | * @param num_spans the number of dropped spans to add back. 44 | */ 45 | void UnconsumeDroppedSpans(int num_spans) noexcept; 46 | 47 | /** 48 | * @return the dropped span count. 49 | */ 50 | int num_dropped_spans() const noexcept { return num_dropped_spans_; } 51 | 52 | private: 53 | MetricsObserver& metrics_observer_; 54 | std::atomic num_dropped_spans_{0}; 55 | }; 56 | } // namespace lightstep 57 | -------------------------------------------------------------------------------- /src/common/platform/network_environment_windows.cpp: -------------------------------------------------------------------------------- 1 | #include "common/platform/network_environment.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "common/platform/error.h" 7 | 8 | #define NOMINMAX 9 | #define WIN32_LEAN_AND_MEAN 10 | #include 11 | #include 12 | #include 13 | 14 | namespace lightstep { 15 | //-------------------------------------------------------------------------------------------------- 16 | // constructor 17 | //-------------------------------------------------------------------------------------------------- 18 | NetworkEnvironment::NetworkEnvironment() { 19 | auto winsock_version_requested = MAKEWORD(2, 2); 20 | WSADATA wsa_data; 21 | auto rcode = WSAStartup(winsock_version_requested, &wsa_data); 22 | if (rcode != 0) { 23 | std::ostringstream oss; 24 | oss << "WSAStartup failed: " 25 | << GetErrorCodeMessage(static_cast(rcode)); 26 | throw std::runtime_error{oss.str()}; 27 | } 28 | if (LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2) { 29 | WSACleanup(); 30 | throw std::runtime_error{"Could not find a suitable Winsock.dll"}; 31 | } 32 | } 33 | 34 | //-------------------------------------------------------------------------------------------------- 35 | // destructor 36 | //-------------------------------------------------------------------------------------------------- 37 | NetworkEnvironment::~NetworkEnvironment() noexcept { WSACleanup(); } 38 | } // namespace lightstep 39 | -------------------------------------------------------------------------------- /src/recorder/stream_recorder/span_stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/chained_stream.h" 4 | #include "common/circular_buffer.h" 5 | #include "recorder/metrics_tracker.h" 6 | 7 | namespace lightstep { 8 | /** 9 | * Manages the stream of data comming from the circular buffer of completed 10 | * spans. 11 | */ 12 | class SpanStream final : public FragmentInputStream { 13 | public: 14 | SpanStream(CircularBuffer& span_buffer, 15 | MetricsTracker& metrics) noexcept; 16 | 17 | /** 18 | * Allots spans from the associated circular buffer to stream to satellites. 19 | */ 20 | void Allot() noexcept; 21 | 22 | /** 23 | * Returns and removes the last partially written span. 24 | * @return the last partially written span 25 | */ 26 | std::unique_ptr ConsumeRemnant() noexcept; 27 | 28 | /** 29 | * @return the associagted MetricsTracker 30 | */ 31 | MetricsTracker& metrics() const noexcept { return metrics_; } 32 | 33 | // FragmentInputStream 34 | int num_fragments() const noexcept override; 35 | 36 | bool ForEachFragment(Callback callback) const noexcept override; 37 | 38 | void Clear() noexcept override; 39 | 40 | void Seek(int fragment_index, int position) noexcept override; 41 | 42 | private: 43 | CircularBuffer& span_buffer_; 44 | MetricsTracker& metrics_; 45 | CircularBufferRange> allotment_; 46 | std::unique_ptr remnant_; 47 | }; 48 | } // namespace lightstep 49 | -------------------------------------------------------------------------------- /src/tracer/propagation/utility.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/utility.h" 4 | 5 | #include 6 | #include 7 | 8 | namespace lightstep { 9 | template 10 | opentracing::expected LookupKey( 11 | const opentracing::TextMapReader& carrier, opentracing::string_view key, 12 | KeyCompare key_compare) { 13 | // First try carrier.LookupKey since that can potentially be the fastest 14 | // approach. 15 | auto result = carrier.LookupKey(key); 16 | if (result || !AreErrorsEqual(result.error(), 17 | opentracing::lookup_key_not_supported_error)) { 18 | return result; 19 | } 20 | 21 | // Fall back to iterating through all of the keys. 22 | result = opentracing::make_unexpected(opentracing::key_not_found_error); 23 | auto was_successful = carrier.ForeachKey( 24 | [&](opentracing::string_view carrier_key, 25 | opentracing::string_view value) -> opentracing::expected { 26 | if (!key_compare(carrier_key, key)) { 27 | return {}; 28 | } 29 | result = value; 30 | 31 | // Found key, so bail out of the loop with a success error code. 32 | return opentracing::make_unexpected(std::error_code{}); 33 | }); 34 | if (!was_successful && was_successful.error() != std::error_code{}) { 35 | return opentracing::make_unexpected(was_successful.error()); 36 | } 37 | return result; 38 | } 39 | } // namespace lightstep 40 | -------------------------------------------------------------------------------- /test/tracer/span_probe.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | int main(int argc, char* argv[]) { 9 | if (argc != 4) { 10 | std::cerr << "Usage: \n"; 11 | return -1; 12 | } 13 | 14 | // Load the tracer library. 15 | std::string error_message; 16 | auto handle_maybe = 17 | opentracing::DynamicallyLoadTracingLibrary(argv[1], error_message); 18 | if (!handle_maybe) { 19 | std::cerr << "Failed to load tracer library " << error_message << "\n"; 20 | return -1; 21 | } 22 | 23 | // Generate the config 24 | auto host = argv[2]; 25 | auto port = argv[3]; 26 | std::ostringstream oss; 27 | oss << R"({ 28 | "component_name" : "span_probe", 29 | "access_token": "abc123", 30 | "collector_plaintext": true, 31 | "use_stream_recorder": true, 32 | "satellite_endpoints": [{"host": ")"; 33 | oss << host << R"(", "port": )" << port; 34 | oss << R"(}]})"; 35 | 36 | // Construct a tracer. 37 | auto& tracer_factory = handle_maybe->tracer_factory(); 38 | auto tracer_maybe = 39 | tracer_factory.MakeTracer(oss.str().c_str(), error_message); 40 | if (!tracer_maybe) { 41 | std::cerr << "Failed to create tracer " << error_message << "\n"; 42 | return -1; 43 | } 44 | auto& tracer = *tracer_maybe; 45 | 46 | // Use the tracer to create some spans. 47 | tracer->StartSpan("A"); 48 | 49 | tracer->Close(); 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /test/network/event_base_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "network/event_base.h" 4 | 5 | #include "3rd_party/catch2/catch.hpp" 6 | 7 | using namespace lightstep; 8 | 9 | TEST_CASE("EventBase") { 10 | EventBase event_base; 11 | 12 | SECTION("EventBase can be move constructed.") { 13 | auto libevent_handle = event_base.libevent_handle(); 14 | REQUIRE(libevent_handle != nullptr); 15 | EventBase event_base2{std::move(event_base)}; 16 | REQUIRE(event_base2.libevent_handle() == libevent_handle); 17 | } 18 | 19 | SECTION("EventBase can be move assigned.") { 20 | auto libevent_handle = event_base.libevent_handle(); 21 | REQUIRE(libevent_handle != nullptr); 22 | EventBase event_base2; 23 | event_base2 = std::move(event_base); 24 | REQUIRE(event_base2.libevent_handle() == libevent_handle); 25 | } 26 | 27 | SECTION("OnTimeout can be used to schedule a 1-off event.") { 28 | bool was_called = false; 29 | auto callback = [](int /*socket*/, short /*what*/, void* context) { 30 | *static_cast(context) = true; 31 | }; 32 | auto exit_callback = [](int /*socket*/, short /*what*/, void* context) { 33 | static_cast(context)->LoopBreak(); 34 | }; 35 | event_base.OnTimeout(std::chrono::milliseconds{5}, callback, 36 | static_cast(&was_called)); 37 | event_base.OnTimeout(std::chrono::milliseconds{10}, exit_callback, 38 | static_cast(&event_base)); 39 | event_base.Dispatch(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /test/recorder/stream_recorder/status_line_parser_test.cpp: -------------------------------------------------------------------------------- 1 | #include "recorder/stream_recorder/status_line_parser.h" 2 | 3 | #include "3rd_party/catch2/catch.hpp" 4 | using namespace lightstep; 5 | 6 | TEST_CASE("StatusLineParser") { 7 | StatusLineParser parser; 8 | REQUIRE(!parser.completed()); 9 | 10 | SECTION("The status line is correctly parsed out of an http response.") { 11 | parser.Parse("HTTP/1.1 200 OK\r\n"); 12 | REQUIRE(parser.completed()); 13 | REQUIRE(parser.status_code() == 200); 14 | REQUIRE(parser.reason() == "OK"); 15 | } 16 | 17 | SECTION("The status line can be parsed in multiple pieces.") { 18 | parser.Parse("HTTP/"); 19 | REQUIRE(!parser.completed()); 20 | parser.Parse("1.1 200 OK\r\n"); 21 | REQUIRE(parser.completed()); 22 | parser.Parse("ignored"); 23 | REQUIRE(parser.completed()); 24 | REQUIRE(parser.status_code() == 200); 25 | REQUIRE(parser.reason() == "OK"); 26 | } 27 | 28 | SECTION("The parser can be reset.") { 29 | parser.Parse("HTTP/1.1 200 OK\r\n"); 30 | REQUIRE(parser.completed()); 31 | parser.Reset(); 32 | REQUIRE(!parser.completed()); 33 | parser.Parse("HTTP/1.1 404 Deadly failure\r\n"); 34 | REQUIRE(parser.completed()); 35 | REQUIRE(parser.status_code() == 404); 36 | REQUIRE(parser.reason() == "Deadly failure"); 37 | } 38 | 39 | SECTION("The parser throws exceptions when given an invalid status line.") { 40 | REQUIRE_THROWS(parser.Parse("abc\r\n")); 41 | REQUIRE_THROWS(parser.Parse(" abc\r\n")); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/common/logger.cpp: -------------------------------------------------------------------------------- 1 | #include "common/logger.h" 2 | #include 3 | #include 4 | 5 | namespace lightstep { 6 | //------------------------------------------------------------------------------ 7 | // LogDefault 8 | //------------------------------------------------------------------------------ 9 | static void LogDefault(LogLevel log_level, 10 | opentracing::string_view message) noexcept try { 11 | std::ostringstream oss; 12 | switch (log_level) { 13 | case LogLevel::debug: 14 | oss << "Debug: "; 15 | break; 16 | case LogLevel::info: 17 | oss << "Info: "; 18 | break; 19 | case LogLevel::warn: 20 | oss << "Warn: "; 21 | break; 22 | case LogLevel::error: 23 | oss << "Error: "; 24 | break; 25 | case LogLevel::off: 26 | /* This should never be reached. */ 27 | return; 28 | } 29 | oss << message << '\n'; 30 | std::cerr << oss.str(); 31 | } catch (const std::exception& /*e*/) { 32 | // Ignore errors. 33 | } 34 | 35 | //------------------------------------------------------------------------------ 36 | // Constructor 37 | //------------------------------------------------------------------------------ 38 | Logger::Logger() : logger_sink_{LogDefault} {} 39 | 40 | Logger::Logger( 41 | std::function&& logger_sink) { 42 | if (logger_sink) { 43 | logger_sink_ = std::move(logger_sink); 44 | } else { 45 | logger_sink_ = LogDefault; 46 | } 47 | } 48 | } // namespace lightstep 49 | -------------------------------------------------------------------------------- /test/baseline_circular_buffer_test.cpp: -------------------------------------------------------------------------------- 1 | #include "test/baseline_circular_buffer.h" 2 | 3 | #include "3rd_party/catch2/catch.hpp" 4 | using namespace lightstep; 5 | 6 | TEST_CASE("CircularBuffer") { 7 | size_t max_elements = 5; 8 | BaselineCircularBuffer buffer{max_elements}; 9 | int count = 0; 10 | 11 | SECTION("The default CircularBuffer is empty") { 12 | buffer.Consume([&](std::unique_ptr&& /*ptr*/) { ++count; }); 13 | REQUIRE(count == 0); 14 | } 15 | 16 | SECTION("We can consume elements out of the circular buffer") { 17 | REQUIRE(buffer.Add(std::unique_ptr{new int{123}})); 18 | buffer.Consume([&](std::unique_ptr&& ptr) { 19 | REQUIRE(*ptr == 123); 20 | ++count; 21 | }); 22 | REQUIRE(count == 1); 23 | } 24 | 25 | SECTION("Add fails if the buffer is full") { 26 | for (size_t i = 0; i < max_elements; ++i) { 27 | REQUIRE(buffer.Add(std::unique_ptr{new int{123}})); 28 | } 29 | REQUIRE(!buffer.Add(std::unique_ptr{new int{123}})); 30 | } 31 | 32 | SECTION("We can consume from a wrapped buffer") { 33 | REQUIRE(buffer.Add(std::unique_ptr{new int{123}})); 34 | REQUIRE(buffer.Add(std::unique_ptr{new int{123}})); 35 | buffer.Consume([&](std::unique_ptr&& /*ptr*/) {}); 36 | for (size_t i = 0; i < max_elements - 1; ++i) { 37 | REQUIRE(buffer.Add(std::unique_ptr{new int{123}})); 38 | } 39 | buffer.Consume([&](std::unique_ptr&& /*ptr*/) { ++count; }); 40 | REQUIRE(count == max_elements - 1); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test/recorder/in_memory_async_transporter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "lightstep-tracer-common/collector.pb.h" 7 | #include "lightstep/transporter.h" 8 | 9 | namespace lightstep { 10 | /** 11 | * An AsyncTransporter that "transports" spans in to a container. 12 | */ 13 | class InMemoryAsyncTransporter final : public AsyncTransporter { 14 | public: 15 | explicit InMemoryAsyncTransporter( 16 | std::function on_span_buffer_full = {}); 17 | 18 | /** 19 | * @return the ReportRequests that were transported. 20 | */ 21 | const std::vector& reports() const noexcept { 22 | return reports_; 23 | } 24 | 25 | /** 26 | * All the spans that were transported. 27 | */ 28 | const std::vector& spans() const noexcept { return spans_; } 29 | 30 | /** 31 | * Make the last Send succeed. 32 | */ 33 | void Succeed() noexcept; 34 | 35 | /** 36 | * Make the last Send fail. 37 | */ 38 | void Fail() noexcept; 39 | 40 | // AsyncTranspoter 41 | void OnSpanBufferFull() noexcept override; 42 | 43 | void Send(std::unique_ptr&& message, 44 | Callback& callback) noexcept override; 45 | 46 | private: 47 | std::function on_span_buffer_full_; 48 | 49 | std::vector reports_; 50 | std::vector spans_; 51 | 52 | Callback* active_callback_{nullptr}; 53 | std::unique_ptr active_message_; 54 | }; 55 | } // namespace lightstep 56 | -------------------------------------------------------------------------------- /src/common/platform/error_unix.cpp: -------------------------------------------------------------------------------- 1 | #include "common/platform/error.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | namespace lightstep { 9 | //-------------------------------------------------------------------------------------------------- 10 | // GetLastErrorCode 11 | //-------------------------------------------------------------------------------------------------- 12 | ErrorCode GetLastErrorCode() noexcept { return errno; } 13 | 14 | //-------------------------------------------------------------------------------------------------- 15 | // GetErrorCodeMessage 16 | //-------------------------------------------------------------------------------------------------- 17 | std::string GetErrorCodeMessage(ErrorCode error_code) { 18 | return std::strerror(error_code); 19 | } 20 | 21 | //-------------------------------------------------------------------------------------------------- 22 | // IsBlockingErrorCode 23 | //-------------------------------------------------------------------------------------------------- 24 | bool IsBlockingErrorCode(ErrorCode error_code) noexcept { 25 | return error_code == EAGAIN || error_code == EWOULDBLOCK; 26 | } 27 | 28 | //-------------------------------------------------------------------------------------------------- 29 | // IsInProgressErrorCode 30 | //-------------------------------------------------------------------------------------------------- 31 | bool IsInProgressErrorCode(ErrorCode error_code) noexcept { 32 | return error_code == EINPROGRESS; 33 | } 34 | } // namespace lightstep 35 | -------------------------------------------------------------------------------- /ci/run_clang_tidy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | CHECKS="\ 6 | -checks=*,\ 7 | -clang-analyzer-core.CallAndMessage,\ 8 | -clang-analyzer-core.NullDereference,\ 9 | -bugprone-use-after-move,\ 10 | -cert-err58-cpp,\ 11 | -fuchsia-*,\ 12 | -clang-analyzer-alpha.*,\ 13 | -clang-diagnostic-deprecated,\ 14 | -llvm-include-order,\ 15 | -llvm-header-guard,\ 16 | -misc-forwarding-reference-overload,\ 17 | -google-runtime-references,\ 18 | -google-build-using-namespace,\ 19 | -google-runtime-int,\ 20 | -google-explicit-constructor,\ 21 | -misc-misplaced-widening-cast,\ 22 | -modernize-make-unique,\ 23 | -modernize-use-transparent-functors,\ 24 | -performance-move-const-arg,\ 25 | -hicpp-explicit-conversions,\ 26 | -hicpp-member-init,\ 27 | -hicpp-invalid-access-moved,\ 28 | -hicpp-move-const-arg,\ 29 | -hicpp-member-init,\ 30 | -hicpp-vararg,\ 31 | -hicpp-signed-bitwise,\ 32 | -hicpp-no-array-decay,\ 33 | -hicpp-special-member-functions,\ 34 | -hicpp-no-assembler,\ 35 | -cppcoreguidelines-pro-type-static-cast-downcast,\ 36 | -cppcoreguidelines-special-member-functions,\ 37 | -cppcoreguidelines-pro-type-union-access,\ 38 | -cppcoreguidelines-pro-type-member-init,\ 39 | -cppcoreguidelines-owning-memory,\ 40 | -cppcoreguidelines-pro-type-reinterpret-cast,\ 41 | -cppcoreguidelines-pro-type-const-cast,\ 42 | -cppcoreguidelines-pro-bounds-array-to-pointer-decay,\ 43 | -cppcoreguidelines-pro-bounds-constant-array-index,\ 44 | -cppcoreguidelines-pro-bounds-pointer-arithmetic,\ 45 | -cppcoreguidelines-pro-type-vararg" 46 | 47 | run-clang-tidy $CHECKS -clang-tidy-binary=ci/clang-tidy-wrapper.sh 48 | -------------------------------------------------------------------------------- /test/common/protobuf_test.cpp: -------------------------------------------------------------------------------- 1 | #include "common/protobuf.h" 2 | 3 | #include 4 | 5 | #include "lightstep-tracer-common/collector.pb.h" 6 | 7 | #include 8 | #include 9 | #include "3rd_party/catch2/catch.hpp" 10 | using namespace lightstep; 11 | 12 | TEST_CASE("Protobuf") { 13 | collector::ReportRequest report; 14 | report.mutable_auth()->set_access_token("abc"); 15 | std::ostringstream oss; 16 | { 17 | google::protobuf::io::OstreamOutputStream zero_copy_stream{&oss}; 18 | google::protobuf::io::CodedOutputStream coded_stream{&zero_copy_stream}; 19 | WriteEmbeddedMessage(coded_stream, 20 | collector::ReportRequest::kAuthFieldNumber, 21 | report.auth()); 22 | } 23 | auto serialization = oss.str(); 24 | 25 | SECTION( 26 | "WriteEmbeddedMessage writes messages that can be read out by " 27 | "protobuf.") { 28 | collector::ReportRequest deserialized_report; 29 | REQUIRE(deserialized_report.ParseFromString(serialization)); 30 | REQUIRE(google::protobuf::util::MessageDifferencer::Equals( 31 | report, deserialized_report)); 32 | } 33 | 34 | SECTION( 35 | "ComputeEmbeddedMessageSerializationSize can be used to compute the " 36 | "serialization size of an embedded message.") { 37 | REQUIRE(serialization.size() == 38 | ComputeEmbeddedMessageSerializationSize( 39 | collector::ReportRequest::kAuthFieldNumber, report.auth())); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /example/stream/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include // for std::getenv 5 | #include 6 | #include 7 | #include 8 | 9 | static void MakeSpan(opentracing::Tracer& tracer, int span_index) { 10 | std::cout << "Make Span: " << span_index << "\n"; 11 | auto span = tracer.StartSpan("span_" + std::to_string(span_index)); 12 | assert(span != nullptr); 13 | for (int tag_index = 0; tag_index < 25; ++tag_index) { 14 | span->SetTag("tag_" + std::to_string(tag_index), tag_index); 15 | } 16 | } 17 | 18 | int main() { 19 | lightstep::LightStepTracerOptions options; 20 | // See https://docs.lightstep.com/docs/developer-mode for instructions on 21 | // setting up a LightStep developer satellite on localhost:8360. 22 | options.collector_plaintext = true; 23 | options.satellite_endpoints = {{"localhost", 8360}}; 24 | options.use_stream_recorder = true; 25 | options.verbose = true; 26 | options.component_name = "Stream"; 27 | if (const char* access_token = std::getenv("LIGHTSTEP_ACCESS_TOKEN")) { 28 | options.access_token = access_token; 29 | } else { 30 | std::cerr << "You must set the environmental variable " 31 | "`LIGHTSTEP_ACCESS_TOKEN` to your access token!\n"; 32 | return -1; 33 | } 34 | 35 | auto tracer = MakeLightStepTracer(std::move(options)); 36 | assert(tracer != nullptr); 37 | for (int i = 0; i < 1000; ++i) { 38 | MakeSpan(*tracer, i); 39 | } 40 | std::cout << "Closing tracer\n"; 41 | tracer->Close(); 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /test/tracer/propagation/lightstep_propagation_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "test/recorder/in_memory_recorder.h" 4 | #include "test/tracer/propagation/http_headers_carrier.h" 5 | #include "test/tracer/propagation/text_map_carrier.h" 6 | #include "test/tracer/propagation/utility.h" 7 | #include "tracer/legacy/legacy_tracer_impl.h" 8 | #include "tracer/tracer_impl.h" 9 | 10 | #include "3rd_party/catch2/catch.hpp" 11 | using namespace lightstep; 12 | 13 | TEST_CASE("lightstep propagation") { 14 | LightStepTracerOptions tracer_options; 15 | tracer_options.propagation_modes = {PropagationMode::b3, 16 | PropagationMode::lightstep}; 17 | auto tracer = std::shared_ptr{ 18 | new TracerImpl{MakePropagationOptions(tracer_options), 19 | std::unique_ptr{new InMemoryRecorder{}}}}; 20 | std::unordered_map text_map; 21 | TextMapCarrier text_map_carrier{text_map}; 22 | HTTPHeadersCarrier http_headers_carrier{text_map}; 23 | 24 | SECTION( 25 | "If a 128-bit trace id is injected via lightstep, it truncates to use " 26 | "the lower part of the id") { 27 | text_map = {{"x-b3-traceid", "aef5705a090040838f1359ebafa5c0c6"}, 28 | {"x-b3-spanid", "aef5705a09004083"}}; 29 | auto span_context_maybe = tracer->Extract(http_headers_carrier); 30 | REQUIRE(span_context_maybe); 31 | text_map.clear(); 32 | REQUIRE(tracer->Inject(**span_context_maybe, text_map_carrier)); 33 | REQUIRE(text_map["ot-tracer-traceid"] == "8f1359ebafa5c0c6"); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/tracer/lightstep_span_context.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "tracer/propagation/propagation.h" 10 | 11 | namespace lightstep { 12 | class LightStepSpanContext : public opentracing::SpanContext { 13 | public: 14 | virtual uint64_t trace_id_high() const noexcept = 0; 15 | 16 | virtual uint64_t trace_id_low() const noexcept = 0; 17 | 18 | virtual uint64_t span_id() const noexcept = 0; 19 | 20 | bool sampled() const noexcept { 21 | return IsTraceFlagSet(this->trace_flags()); 22 | } 23 | 24 | virtual uint8_t trace_flags() const noexcept = 0; 25 | 26 | virtual opentracing::string_view trace_state() const noexcept = 0; 27 | 28 | virtual opentracing::expected Inject( 29 | const PropagationOptions& propagation_options, 30 | std::ostream& writer) const = 0; 31 | 32 | virtual opentracing::expected Inject( 33 | const PropagationOptions& propagation_options, 34 | const opentracing::TextMapWriter& writer) const = 0; 35 | 36 | virtual opentracing::expected Inject( 37 | const PropagationOptions& propagation_options, 38 | const opentracing::HTTPHeadersWriter& writer) const = 0; 39 | }; 40 | 41 | bool operator==(const LightStepSpanContext& lhs, 42 | const LightStepSpanContext& rhs); 43 | 44 | inline bool operator!=(const LightStepSpanContext& lhs, 45 | const LightStepSpanContext& rhs) { 46 | return !(lhs == rhs); 47 | } 48 | } // namespace lightstep 49 | -------------------------------------------------------------------------------- /test/tracer/propagation/utility.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "tracer/lightstep_span_context.h" 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | namespace lightstep { 11 | inline bool AreSpanContextsEquivalent( 12 | const opentracing::SpanContext& context1, 13 | const opentracing::SpanContext& context2) { 14 | return dynamic_cast(context1) == 15 | dynamic_cast(context2); 16 | } 17 | 18 | template 19 | void VerifyInjectExtract(const opentracing::Tracer& tracer, 20 | const opentracing::SpanContext& span_context, 21 | Carrier& carrier) { 22 | auto rcode = tracer.Inject(span_context, carrier); 23 | if (!rcode) { 24 | throw std::runtime_error{"failed to inject span context: " + 25 | rcode.error().message()}; 26 | } 27 | auto span_context_maybe = tracer.Extract(carrier); 28 | if (!span_context_maybe) { 29 | throw std::runtime_error{"failed to extract span context: " + 30 | span_context_maybe.error().message()}; 31 | } 32 | if (*span_context_maybe == nullptr) { 33 | throw std::runtime_error{"no span context extracted"}; 34 | } 35 | 36 | if (!AreSpanContextsEquivalent(span_context, **span_context_maybe)) { 37 | throw std::runtime_error{"span contexts not equal"}; 38 | } 39 | } 40 | 41 | std::vector> MakeTestSpanContexts( 42 | bool use_128bit_trace_ids = false); 43 | } // namespace lightstep 44 | -------------------------------------------------------------------------------- /src/tracer/propagation/envoy_propagator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "tracer/propagation/propagator.h" 4 | 5 | namespace lightstep { 6 | /** 7 | * Propagator for Envoy's single-header format. 8 | */ 9 | class EnvoyPropagator final : public Propagator { 10 | public: 11 | // Propagator 12 | opentracing::expected InjectSpanContext( 13 | const opentracing::TextMapWriter& carrier, 14 | const TraceContext& trace_context, opentracing::string_view trace_state, 15 | const BaggageProtobufMap& baggage) const override; 16 | 17 | opentracing::expected InjectSpanContext( 18 | const opentracing::TextMapWriter& carrier, 19 | const TraceContext& trace_context, opentracing::string_view trace_state, 20 | const BaggageFlatMap& baggage) const override; 21 | 22 | opentracing::expected ExtractSpanContext( 23 | const opentracing::TextMapReader& carrier, bool case_sensitive, 24 | TraceContext& trace_context, std::string& trace_state, 25 | BaggageProtobufMap& baggage) const override; 26 | 27 | private: 28 | template 29 | opentracing::expected InjectSpanContextImpl( 30 | const opentracing::TextMapWriter& carrier, 31 | const TraceContext& trace_context, const BaggageMap& baggage) const; 32 | 33 | template 34 | opentracing::expected ExtractSpanContextImpl( 35 | const opentracing::TextMapReader& carrier, uint64_t& trace_id_high, 36 | uint64_t& trace_id_low, uint64_t& span_id, bool& sampled, 37 | BaggageProtobufMap& baggage, const KeyCompare& key_compare) const; 38 | }; 39 | } // namespace lightstep 40 | -------------------------------------------------------------------------------- /test/common/composable_fragment_input_stream_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "3rd_party/catch2/catch.hpp" 4 | #include "common/composable_fragment_input_stream.h" 5 | #include "common/fragment_array_input_stream.h" 6 | #include "test/composable_fragment_input_stream_wrapper.h" 7 | #include "test/utility.h" 8 | using namespace lightstep; 9 | 10 | TEST_CASE("ComposableFragmentInputStream") { 11 | ComposableFragmentInputStreamWrapper stream{ 12 | std::unique_ptr{new FragmentArrayInputStream{ 13 | MakeFragment("abc"), MakeFragment("123")}}}; 14 | stream.Append(std::unique_ptr{ 15 | new ComposableFragmentInputStreamWrapper{ 16 | std::unique_ptr{new FragmentArrayInputStream{ 17 | MakeFragment("xyz"), MakeFragment("456")}}}}); 18 | REQUIRE(ToString(stream) == "abc123xyz456"); 19 | REQUIRE(stream.num_fragments() == 4); 20 | 21 | stream.Append(std::unique_ptr{ 22 | new ComposableFragmentInputStreamWrapper{ 23 | std::unique_ptr{ 24 | new FragmentArrayInputStream{MakeFragment("qrz")}}}}); 25 | REQUIRE(ToString(stream) == "abc123xyz456qrz"); 26 | REQUIRE(stream.num_fragments() == 5); 27 | 28 | SECTION("We can consume from ComposableFragmentInputStream") { 29 | auto contents = ToString(stream); 30 | for (size_t i = 0; i < contents.size(); ++i) { 31 | SECTION("Consume " + std::to_string(i)) { 32 | Consume({&stream}, i); 33 | REQUIRE(ToString(stream) == contents.substr(i)); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/common/platform/BUILD: -------------------------------------------------------------------------------- 1 | load( 2 | "//bazel:lightstep_build_system.bzl", 3 | "lightstep_cc_library", 4 | "lightstep_package", 5 | ) 6 | 7 | lightstep_package() 8 | 9 | lightstep_cc_library( 10 | name = "error_lib", 11 | private_hdrs = [ 12 | "error.h", 13 | ], 14 | srcs = [ 15 | "error_unix.cpp", 16 | ], 17 | ) 18 | 19 | lightstep_cc_library( 20 | name = "memory_lib", 21 | private_hdrs = [ 22 | "memory.h", 23 | ], 24 | ) 25 | 26 | lightstep_cc_library( 27 | name = "network_lib", 28 | private_hdrs = [ 29 | "network.h", 30 | ], 31 | srcs = [ 32 | "network_unix.cpp", 33 | ], 34 | ) 35 | 36 | lightstep_cc_library( 37 | name = "network_environment_lib", 38 | private_hdrs = [ 39 | "network_environment.h", 40 | ], 41 | srcs = [ 42 | "network_environment_unix.cpp", 43 | ], 44 | deps = [ 45 | ":error_lib", 46 | ], 47 | ) 48 | 49 | lightstep_cc_library( 50 | name = "fork_lib", 51 | private_hdrs = [ 52 | "fork.h", 53 | ], 54 | srcs = [ 55 | "fork_unix.cpp", 56 | ], 57 | ) 58 | 59 | lightstep_cc_library( 60 | name = "string_lib", 61 | private_hdrs = [ 62 | "string.h", 63 | ], 64 | srcs = [ 65 | "string_unix.cpp", 66 | ], 67 | ) 68 | 69 | lightstep_cc_library( 70 | name = "time_lib", 71 | private_hdrs = [ 72 | "time.h", 73 | ], 74 | ) 75 | 76 | lightstep_cc_library( 77 | name = "utility_lib", 78 | private_hdrs = [ 79 | "utility.h", 80 | ], 81 | srcs = [ 82 | "utility_unix.cpp", 83 | ], 84 | ) 85 | -------------------------------------------------------------------------------- /ci/fix_compilation_database.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # Taken from https://github.com/envoyproxy/envoy/blob/964dd1de5d4d4cb388a0e6dd25dbff1f7ff56cea/tools/gen_compilation_database.py with modification. 4 | 5 | import json 6 | import sys 7 | import os 8 | 9 | def isHeader(filename): 10 | for ext in (".h", ".hh", ".hpp", ".hxx"): 11 | if filename.endswith(ext): 12 | return True 13 | return False 14 | 15 | def isCompileTarget(target): 16 | filename = target["file"] 17 | 18 | if filename.startswith("3rd_party"): 19 | return False 20 | 21 | if filename.startswith("bazel-out/"): 22 | return False 23 | 24 | if filename.startswith("external/"): 25 | return False 26 | 27 | return True 28 | 29 | def modifyCompileCommand(target): 30 | cxx, options = target["command"].split(" ", 1) 31 | 32 | # Workaround for bazel added C++11 options, those doesn't affect build itself but 33 | # clang-tidy will misinterpret them. 34 | options = options.replace("-std=c++0x ", "") 35 | options = options.replace("-std=c++11 ", "") 36 | 37 | if isHeader(target["file"]): 38 | options += " -Wno-pragma-once-outside-header -Wno-unused-const-variable" 39 | options += " -Wno-unused-function" 40 | options += " -x c++-header" 41 | 42 | target["command"] = " ".join(["clang++", options]) 43 | return target 44 | 45 | with open("compile_commands.json", "r") as db_file: 46 | db = json.load(db_file) 47 | 48 | db = [modifyCompileCommand(target) for target in db if isCompileTarget(target)] 49 | os.remove("compile_commands.json") 50 | 51 | with open("compile_commands.json", "w") as db_file: 52 | json.dump(db, db_file, indent=2) 53 | -------------------------------------------------------------------------------- /src/network/timer_event.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/platform/time.h" 4 | #include "network/event.h" 5 | #include "network/event_base.h" 6 | 7 | struct event; 8 | 9 | namespace lightstep { 10 | /** 11 | * Manages a periodic timer event. 12 | */ 13 | class TimerEvent { 14 | public: 15 | TimerEvent() noexcept = default; 16 | 17 | template 18 | TimerEvent(const EventBase& event_base, 19 | std::chrono::duration interval, 20 | Event::Callback callback, void* context) 21 | : TimerEvent{ 22 | event_base, 23 | std::chrono::duration_cast(interval), 24 | callback, context} {} 25 | 26 | TimerEvent(const EventBase& event_base, std::chrono::microseconds interval, 27 | Event::Callback callback, void* context); 28 | 29 | TimerEvent(const EventBase& event_base, Event::Callback callback, 30 | void* context); 31 | 32 | /** 33 | * Resets the timer to start anew from now. 34 | */ 35 | void Reset(); 36 | 37 | void Reset(const timeval* tv); 38 | 39 | private: 40 | Event event_; 41 | timeval tv_{}; 42 | }; 43 | 44 | /** 45 | * For a given method, creates a timer callback function that can be passed to 46 | * libevent. 47 | * @return a function pointer that can be passed to libevent. 48 | */ 49 | template 50 | Event::Callback MakeTimerCallback() noexcept { 51 | return [](FileDescriptor /*socket*/, short /*what*/, void* context) noexcept { 52 | (static_cast(context)->*MemberFunction)(); 53 | }; 54 | } 55 | } // namespace lightstep 56 | -------------------------------------------------------------------------------- /src/recorder/stream_recorder/satellite_endpoint_manager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "common/noncopyable.h" 8 | #include "lightstep/tracer.h" 9 | #include "network/dns_resolver.h" 10 | #include "recorder/stream_recorder/satellite_dns_resolution_manager.h" 11 | 12 | namespace lightstep { 13 | /** 14 | * Manages the resolution and assignment of satellite endpoints. 15 | */ 16 | class SatelliteEndpointManager : private Noncopyable { 17 | struct SatelliteHostManager { 18 | std::unique_ptr ipv4_resolutions; 19 | std::unique_ptr ipv6_resolutions; 20 | uint32_t address_index{0}; 21 | }; 22 | 23 | public: 24 | SatelliteEndpointManager(Logger& logger, EventBase& event_base, 25 | const LightStepTracerOptions& tracer_options, 26 | const StreamRecorderOptions& recorder_options, 27 | std::function on_ready_callback); 28 | 29 | /** 30 | * Start resolving hosts to ip addresses. 31 | */ 32 | void Start() noexcept; 33 | 34 | /** 35 | * Assigns satellite endpoints using round robin. 36 | * @return a satellite endpoint. 37 | */ 38 | std::pair RequestEndpoint() noexcept; 39 | 40 | private: 41 | std::function on_ready_callback_; 42 | std::vector host_managers_; 43 | std::vector> endpoints_; 44 | uint32_t endpoint_index_{0}; 45 | int num_resolutions_ready_{0}; 46 | 47 | void OnResolutionReady() noexcept; 48 | }; 49 | } // namespace lightstep 50 | -------------------------------------------------------------------------------- /src/network/socket.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "network/ip_address.h" 4 | 5 | namespace lightstep { 6 | /** 7 | * Wraps a system socket structure. 8 | */ 9 | class Socket { 10 | public: 11 | Socket(); 12 | 13 | Socket(int family, int type); 14 | 15 | explicit Socket(FileDescriptor file_descriptor) noexcept; 16 | 17 | Socket(const Socket&) = delete; 18 | 19 | Socket(Socket&& other) noexcept; 20 | 21 | ~Socket() noexcept; 22 | 23 | Socket& operator=(Socket&& other) noexcept; 24 | 25 | Socket& operator=(const Socket&) = delete; 26 | 27 | /** 28 | * @return the file descriptor for this socket. 29 | */ 30 | FileDescriptor file_descriptor() const noexcept { return file_descriptor_; } 31 | 32 | /** 33 | * Makes the socket non-blocking. 34 | */ 35 | void SetNonblocking(); 36 | 37 | /** 38 | * Makes the socket's address be reusable. 39 | */ 40 | void SetReuseAddress(); 41 | 42 | /** 43 | * Establishes a connection to a given address. 44 | * @param addr supplies the sockaddr to connect to. 45 | * @param addrlen supplies the length of the address. 46 | * @return the return code of the system call ::connect. 47 | */ 48 | int Connect(const sockaddr& addr, size_t addrlen) noexcept; 49 | 50 | private: 51 | FileDescriptor file_descriptor_{InvalidSocket}; 52 | 53 | void Free() noexcept; 54 | }; 55 | 56 | /** 57 | * Establishes a connetion to a provided address. 58 | * @param ip_address supplies the address to connect to. 59 | * @param type supplies the type of connection. 60 | * @return a non-blocking Socket for the connection. 61 | */ 62 | Socket Connect(const IpAddress& ip_address); 63 | } // namespace lightstep 64 | -------------------------------------------------------------------------------- /src/tracer/dynamic_load.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "tracer/lightstep_tracer_factory.h" 5 | 6 | static int OpenTracingMakeTracerFactoryFunction( 7 | const char* opentracing_version, const char* opentracing_abi_version, 8 | const void** error_category, void* error_message, 9 | void** tracer_factory) try { 10 | if (opentracing_version == nullptr || opentracing_abi_version == nullptr || 11 | error_message == nullptr || error_category == nullptr || 12 | tracer_factory == nullptr) { 13 | fprintf(stderr, 14 | "`opentracing_version`, `opentracing_abi_version`, " 15 | "`error_message`, `error_category`, and `tracer_factory` must be " 16 | "non-null.\n"); 17 | std::terminate(); 18 | } 19 | 20 | if (std::strcmp(opentracing_abi_version, OPENTRACING_ABI_VERSION) != 0) { 21 | *error_category = 22 | static_cast(&opentracing::dynamic_load_error_category()); 23 | auto& message = *static_cast(error_message); 24 | message = 25 | "incompatible OpenTracing ABI versions; " 26 | "expected " OPENTRACING_ABI_VERSION " but got "; 27 | message.append(opentracing_abi_version); 28 | return opentracing::incompatible_library_versions_error.value(); 29 | } 30 | 31 | *tracer_factory = new lightstep::LightStepTracerFactory{}; 32 | 33 | return 0; 34 | } catch (const std::bad_alloc&) { 35 | *error_category = static_cast(&std::generic_category()); 36 | return static_cast(std::errc::not_enough_memory); 37 | } 38 | 39 | OPENTRACING_DECLARE_IMPL_FACTORY(OpenTracingMakeTracerFactoryFunction) 40 | -------------------------------------------------------------------------------- /src/recorder/manual_recorder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "common/circular_buffer.h" 6 | #include "common/logger.h" 7 | #include "common/noncopyable.h" 8 | #include "lightstep/transporter.h" 9 | #include "recorder/fork_aware_recorder.h" 10 | #include "recorder/metrics_tracker.h" 11 | 12 | namespace lightstep { 13 | /** 14 | * Implements a Recorder with no background thread and custom Transporter. 15 | */ 16 | class ManualRecorder : public ForkAwareRecorder, 17 | public AsyncTransporter::Callback, 18 | private Noncopyable { 19 | public: 20 | ManualRecorder(Logger& logger, LightStepTracerOptions options, 21 | std::unique_ptr&& transporter); 22 | 23 | // Recorder 24 | Fragment ReserveHeaderSpace(ChainedStream& stream) override; 25 | 26 | void RecordSpan(Fragment header_fragment, 27 | std::unique_ptr&& span) noexcept override; 28 | 29 | bool FlushWithTimeout( 30 | std::chrono::system_clock::duration timeout) noexcept override; 31 | 32 | // ForkAwareRecorder 33 | void OnForkedChild() noexcept override; 34 | 35 | // AsyncTransporter::Callback 36 | void OnSuccess(BufferChain& message) noexcept override; 37 | 38 | void OnFailure(BufferChain& message) noexcept override; 39 | 40 | private: 41 | Logger& logger_; 42 | LightStepTracerOptions tracer_options_; 43 | std::unique_ptr transporter_; 44 | std::shared_ptr report_request_header_; 45 | 46 | MetricsTracker metrics_; 47 | std::mutex flush_mutex_; 48 | CircularBuffer span_buffer_; 49 | }; 50 | } // namespace lightstep 51 | --------------------------------------------------------------------------------