├── .circleci └── config.yml ├── .gitignore ├── 3rd_party ├── embedfile │ └── src │ │ └── embedfile.c └── include │ └── zipkin │ ├── catch │ ├── LICENSE.txt │ └── catch.hpp │ ├── randutils │ ├── LICENSE │ └── randutils.h │ └── rapidjson │ ├── allocators.h │ ├── document.h │ ├── encodedstream.h │ ├── encodings.h │ ├── error │ ├── en.h │ └── error.h │ ├── filereadstream.h │ ├── filewritestream.h │ ├── fwd.h │ ├── internal │ ├── biginteger.h │ ├── diyfp.h │ ├── dtoa.h │ ├── ieee754.h │ ├── itoa.h │ ├── meta.h │ ├── pow10.h │ ├── regex.h │ ├── stack.h │ ├── strfunc.h │ ├── strtod.h │ └── swap.h │ ├── istreamwrapper.h │ ├── license.txt │ ├── memorybuffer.h │ ├── memorystream.h │ ├── msinttypes │ ├── inttypes.h │ └── stdint.h │ ├── ostreamwrapper.h │ ├── pointer.h │ ├── prettywriter.h │ ├── rapidjson.h │ ├── reader.h │ ├── schema.h │ ├── stream.h │ ├── stringbuffer.h │ └── writer.h ├── BUILD ├── CMakeLists.txt ├── LICENSE ├── README.md ├── WORKSPACE ├── ci ├── BUILD.curl ├── WORKSPACE ├── build_plugin.sh ├── do_ci.sh ├── install_bazel.sh ├── install_dependencies.sh └── release.sh ├── scripts ├── run_clang_format.sh └── runldconfig ├── zipkin ├── CMakeLists.txt ├── include │ └── zipkin │ │ ├── flags.h │ │ ├── hex.h │ │ ├── ip_address.h │ │ ├── optional.h │ │ ├── span_context.h │ │ ├── trace_id.h │ │ ├── tracer.h │ │ ├── tracer_interface.h │ │ ├── utility.h │ │ └── zipkin_core_types.h ├── src │ ├── hex.cc │ ├── ip_address.cc │ ├── singleton.h │ ├── span_buffer.cc │ ├── span_buffer.h │ ├── span_context.cc │ ├── tracer.cc │ ├── transporter.h │ ├── utility.cc │ ├── zipkin_core_constants.h │ ├── zipkin_core_types.cc │ ├── zipkin_http_transporter.cc │ ├── zipkin_http_transporter.h │ ├── zipkin_json_field_names.h │ ├── zipkin_reporter_impl.cc │ └── zipkin_reporter_impl.h └── test │ ├── CMakeLists.txt │ └── hex_test.cc └── zipkin_opentracing ├── CMakeLists.txt ├── example ├── CMakeLists.txt ├── text_map_carrier.h └── tutorial.cc ├── include └── zipkin │ └── opentracing.h ├── src ├── dynamic_load.cc ├── opentracing.cc ├── propagation.cc ├── propagation.h ├── sampling.cc ├── sampling.h ├── tracer_factory.cc ├── tracer_factory.h ├── utility.cc └── utility.h ├── test ├── CMakeLists.txt ├── in_memory_reporter.h ├── ot_tracer_factory_test.cc └── ot_tracer_test.cc └── tracer_configuration.schema.json /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | asan: 4 | docker: 5 | - image: ubuntu:18.04 6 | steps: 7 | - checkout 8 | - run: ./ci/install_dependencies.sh 9 | - run: ./ci/do_ci.sh cmake.asan 10 | - store_artifacts: 11 | path: /build/Testing/Temporary/LastTest.log 12 | destination: Test.log 13 | tsan: 14 | docker: 15 | - image: ubuntu:18.04 16 | steps: 17 | - checkout 18 | - run: mkdir -p /build 19 | - run: ./ci/install_dependencies.sh 20 | - run: BUILD_DIR=/build ./ci/do_ci.sh cmake.tsan 21 | - store_artifacts: 22 | path: /build/Testing/Temporary/LastTest.log 23 | destination: Test.log 24 | bazel: 25 | docker: 26 | - image: ubuntu:18.04 27 | steps: 28 | - checkout 29 | - run: ./ci/install_dependencies.sh 30 | - run: ./ci/install_bazel.sh 31 | - run: ./ci/do_ci.sh bazel.build 32 | plugin: 33 | docker: 34 | - image: ubuntu:18.04 35 | steps: 36 | - checkout 37 | - run: ./ci/do_ci.sh cmake.plugin 38 | - store_artifacts: 39 | path: /libzipkin_opentracing_plugin.so 40 | destination: libzipkin_opentracing_plugin.so 41 | release: 42 | docker: 43 | - image: ubuntu:18.04 44 | steps: 45 | - run: apt-get -qq update; apt-get -y install git ssh 46 | - checkout 47 | - run: ./ci/do_ci.sh release 48 | 49 | workflows: 50 | version: 2 51 | build_test_and_deploy: 52 | jobs: 53 | - release: 54 | filters: 55 | branches: 56 | ignore: /.*/ 57 | tags: 58 | only: /^v[0-9]+(\.[0-9]+)*$/ 59 | - asan 60 | - tsan 61 | - bazel 62 | - plugin 63 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | bazel-* 35 | 36 | .build/ 37 | -------------------------------------------------------------------------------- /3rd_party/embedfile/src/embedfile.c: -------------------------------------------------------------------------------- 1 | // Taken from https://stackoverflow.com/a/11814544/4447365 2 | 3 | #include 4 | #include 5 | 6 | FILE* open_or_exit(const char* fname, const char* mode) 7 | { 8 | FILE* f = fopen(fname, mode); 9 | if (f == NULL) { 10 | perror(fname); 11 | exit(EXIT_FAILURE); 12 | } 13 | return f; 14 | } 15 | 16 | int main(int argc, char** argv) 17 | { 18 | if (argc < 3) { 19 | fprintf(stderr, "USAGE: %s {sym} {rsrc}\n\n" 20 | " Creates {sym}.cpp from the contents of {rsrc}\n", 21 | argv[0]); 22 | return EXIT_FAILURE; 23 | } 24 | 25 | const char* sym = argv[1]; 26 | FILE* in = open_or_exit(argv[2], "r"); 27 | 28 | char symfile[256]; 29 | snprintf(symfile, sizeof(symfile), "%s.cpp", sym); 30 | 31 | FILE* out = open_or_exit(symfile,"w"); 32 | fprintf(out, "namespace zipkin {\n"); 33 | fprintf(out, "extern const unsigned char %s[];\n", sym); 34 | fprintf(out, "extern const int %s_size;\n", sym); 35 | fprintf(out, "const unsigned char %s[] = {\n", sym); 36 | 37 | unsigned char buf[256]; 38 | size_t nread = 0; 39 | size_t linecount = 0; 40 | do { 41 | nread = fread(buf, 1, sizeof(buf), in); 42 | size_t i; 43 | for (i=0; i < nread; i++) { 44 | fprintf(out, "0x%02x, ", buf[i]); 45 | if (++linecount == 10) { fprintf(out, "\n"); linecount = 0; } 46 | } 47 | } while (nread > 0); 48 | if (linecount > 0) fprintf(out, "\n"); 49 | fprintf(out, "};\n"); 50 | fprintf(out, "const int %s_size = static_cast(sizeof(%s));\n\n",sym,sym); 51 | fprintf(out, "} //namespace zipkin\n"); 52 | 53 | fclose(in); 54 | fclose(out); 55 | 56 | return EXIT_SUCCESS; 57 | } 58 | -------------------------------------------------------------------------------- /3rd_party/include/zipkin/catch/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 | -------------------------------------------------------------------------------- /3rd_party/include/zipkin/randutils/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /3rd_party/include/zipkin/rapidjson/error/en.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_ERROR_EN_H_ 16 | #define RAPIDJSON_ERROR_EN_H_ 17 | 18 | #include "error.h" 19 | 20 | #ifdef __clang__ 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(switch-enum) 23 | RAPIDJSON_DIAG_OFF(covered-switch-default) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Maps error code of parsing into error message. 29 | /*! 30 | \ingroup RAPIDJSON_ERRORS 31 | \param parseErrorCode Error code obtained in parsing. 32 | \return the error message. 33 | \note User can make a copy of this function for localization. 34 | Using switch-case is safer for future modification of error codes. 35 | */ 36 | inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { 37 | switch (parseErrorCode) { 38 | case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); 39 | 40 | case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); 41 | case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values."); 42 | 43 | case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); 44 | 45 | case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); 46 | case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); 47 | case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); 48 | 49 | case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); 50 | 51 | case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); 52 | case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); 53 | case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); 54 | case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); 55 | case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); 56 | 57 | case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); 58 | case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); 59 | case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); 60 | 61 | case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); 62 | case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); 63 | 64 | default: return RAPIDJSON_ERROR_STRING("Unknown error."); 65 | } 66 | } 67 | 68 | RAPIDJSON_NAMESPACE_END 69 | 70 | #ifdef __clang__ 71 | RAPIDJSON_DIAG_POP 72 | #endif 73 | 74 | #endif // RAPIDJSON_ERROR_EN_H_ 75 | -------------------------------------------------------------------------------- /3rd_party/include/zipkin/rapidjson/error/error.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_ERROR_ERROR_H_ 16 | #define RAPIDJSON_ERROR_ERROR_H_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | #ifdef __clang__ 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(padded) 23 | #endif 24 | 25 | /*! \file error.h */ 26 | 27 | /*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */ 28 | 29 | /////////////////////////////////////////////////////////////////////////////// 30 | // RAPIDJSON_ERROR_CHARTYPE 31 | 32 | //! Character type of error messages. 33 | /*! \ingroup RAPIDJSON_ERRORS 34 | The default character type is \c char. 35 | On Windows, user can define this macro as \c TCHAR for supporting both 36 | unicode/non-unicode settings. 37 | */ 38 | #ifndef RAPIDJSON_ERROR_CHARTYPE 39 | #define RAPIDJSON_ERROR_CHARTYPE char 40 | #endif 41 | 42 | /////////////////////////////////////////////////////////////////////////////// 43 | // RAPIDJSON_ERROR_STRING 44 | 45 | //! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[]. 46 | /*! \ingroup RAPIDJSON_ERRORS 47 | By default this conversion macro does nothing. 48 | On Windows, user can define this macro as \c _T(x) for supporting both 49 | unicode/non-unicode settings. 50 | */ 51 | #ifndef RAPIDJSON_ERROR_STRING 52 | #define RAPIDJSON_ERROR_STRING(x) x 53 | #endif 54 | 55 | RAPIDJSON_NAMESPACE_BEGIN 56 | 57 | /////////////////////////////////////////////////////////////////////////////// 58 | // ParseErrorCode 59 | 60 | //! Error code of parsing. 61 | /*! \ingroup RAPIDJSON_ERRORS 62 | \see GenericReader::Parse, GenericReader::GetParseErrorCode 63 | */ 64 | enum ParseErrorCode { 65 | kParseErrorNone = 0, //!< No error. 66 | 67 | kParseErrorDocumentEmpty, //!< The document is empty. 68 | kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. 69 | 70 | kParseErrorValueInvalid, //!< Invalid value. 71 | 72 | kParseErrorObjectMissName, //!< Missing a name for object member. 73 | kParseErrorObjectMissColon, //!< Missing a colon after a name of object member. 74 | kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member. 75 | 76 | kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element. 77 | 78 | kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string. 79 | kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. 80 | kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. 81 | kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. 82 | kParseErrorStringInvalidEncoding, //!< Invalid encoding in string. 83 | 84 | kParseErrorNumberTooBig, //!< Number too big to be stored in double. 85 | kParseErrorNumberMissFraction, //!< Miss fraction part in number. 86 | kParseErrorNumberMissExponent, //!< Miss exponent in number. 87 | 88 | kParseErrorTermination, //!< Parsing was terminated. 89 | kParseErrorUnspecificSyntaxError //!< Unspecific syntax error. 90 | }; 91 | 92 | //! Result of parsing (wraps ParseErrorCode) 93 | /*! 94 | \ingroup RAPIDJSON_ERRORS 95 | \code 96 | Document doc; 97 | ParseResult ok = doc.Parse("[42]"); 98 | if (!ok) { 99 | fprintf(stderr, "JSON parse error: %s (%u)", 100 | GetParseError_En(ok.Code()), ok.Offset()); 101 | exit(EXIT_FAILURE); 102 | } 103 | \endcode 104 | \see GenericReader::Parse, GenericDocument::Parse 105 | */ 106 | struct ParseResult { 107 | public: 108 | //! Default constructor, no error. 109 | ParseResult() : code_(kParseErrorNone), offset_(0) {} 110 | //! Constructor to set an error. 111 | ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} 112 | 113 | //! Get the error code. 114 | ParseErrorCode Code() const { return code_; } 115 | //! Get the error offset, if \ref IsError(), 0 otherwise. 116 | size_t Offset() const { return offset_; } 117 | 118 | //! Conversion to \c bool, returns \c true, iff !\ref IsError(). 119 | operator bool() const { return !IsError(); } 120 | //! Whether the result is an error. 121 | bool IsError() const { return code_ != kParseErrorNone; } 122 | 123 | bool operator==(const ParseResult& that) const { return code_ == that.code_; } 124 | bool operator==(ParseErrorCode code) const { return code_ == code; } 125 | friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } 126 | 127 | //! Reset error code. 128 | void Clear() { Set(kParseErrorNone); } 129 | //! Update error code and offset. 130 | void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } 131 | 132 | private: 133 | ParseErrorCode code_; 134 | size_t offset_; 135 | }; 136 | 137 | //! Function pointer type of GetParseError(). 138 | /*! \ingroup RAPIDJSON_ERRORS 139 | 140 | This is the prototype for \c GetParseError_X(), where \c X is a locale. 141 | User can dynamically change locale in runtime, e.g.: 142 | \code 143 | GetParseErrorFunc GetParseError = GetParseError_En; // or whatever 144 | const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode()); 145 | \endcode 146 | */ 147 | typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode); 148 | 149 | RAPIDJSON_NAMESPACE_END 150 | 151 | #ifdef __clang__ 152 | RAPIDJSON_DIAG_POP 153 | #endif 154 | 155 | #endif // RAPIDJSON_ERROR_ERROR_H_ 156 | -------------------------------------------------------------------------------- /3rd_party/include/zipkin/rapidjson/filereadstream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_FILEREADSTREAM_H_ 16 | #define RAPIDJSON_FILEREADSTREAM_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | 21 | #ifdef __clang__ 22 | RAPIDJSON_DIAG_PUSH 23 | RAPIDJSON_DIAG_OFF(padded) 24 | RAPIDJSON_DIAG_OFF(unreachable-code) 25 | RAPIDJSON_DIAG_OFF(missing-noreturn) 26 | #endif 27 | 28 | RAPIDJSON_NAMESPACE_BEGIN 29 | 30 | //! File byte stream for input using fread(). 31 | /*! 32 | \note implements Stream concept 33 | */ 34 | class FileReadStream { 35 | public: 36 | typedef char Ch; //!< Character type (byte). 37 | 38 | //! Constructor. 39 | /*! 40 | \param fp File pointer opened for read. 41 | \param buffer user-supplied buffer. 42 | \param bufferSize size of buffer in bytes. Must >=4 bytes. 43 | */ 44 | FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { 45 | RAPIDJSON_ASSERT(fp_ != 0); 46 | RAPIDJSON_ASSERT(bufferSize >= 4); 47 | Read(); 48 | } 49 | 50 | Ch Peek() const { return *current_; } 51 | Ch Take() { Ch c = *current_; Read(); return c; } 52 | size_t Tell() const { return count_ + static_cast(current_ - buffer_); } 53 | 54 | // Not implemented 55 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 56 | void Flush() { RAPIDJSON_ASSERT(false); } 57 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 58 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 59 | 60 | // For encoding detection only. 61 | const Ch* Peek4() const { 62 | return (current_ + 4 <= bufferLast_) ? current_ : 0; 63 | } 64 | 65 | private: 66 | void Read() { 67 | if (current_ < bufferLast_) 68 | ++current_; 69 | else if (!eof_) { 70 | count_ += readCount_; 71 | readCount_ = fread(buffer_, 1, bufferSize_, fp_); 72 | bufferLast_ = buffer_ + readCount_ - 1; 73 | current_ = buffer_; 74 | 75 | if (readCount_ < bufferSize_) { 76 | buffer_[readCount_] = '\0'; 77 | ++bufferLast_; 78 | eof_ = true; 79 | } 80 | } 81 | } 82 | 83 | std::FILE* fp_; 84 | Ch *buffer_; 85 | size_t bufferSize_; 86 | Ch *bufferLast_; 87 | Ch *current_; 88 | size_t readCount_; 89 | size_t count_; //!< Number of characters read 90 | bool eof_; 91 | }; 92 | 93 | RAPIDJSON_NAMESPACE_END 94 | 95 | #ifdef __clang__ 96 | RAPIDJSON_DIAG_POP 97 | #endif 98 | 99 | #endif // RAPIDJSON_FILESTREAM_H_ 100 | -------------------------------------------------------------------------------- /3rd_party/include/zipkin/rapidjson/filewritestream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_FILEWRITESTREAM_H_ 16 | #define RAPIDJSON_FILEWRITESTREAM_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | 21 | #ifdef __clang__ 22 | RAPIDJSON_DIAG_PUSH 23 | RAPIDJSON_DIAG_OFF(unreachable-code) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Wrapper of C file stream for input using fread(). 29 | /*! 30 | \note implements Stream concept 31 | */ 32 | class FileWriteStream { 33 | public: 34 | typedef char Ch; //!< Character type. Only support char. 35 | 36 | FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { 37 | RAPIDJSON_ASSERT(fp_ != 0); 38 | } 39 | 40 | void Put(char c) { 41 | if (current_ >= bufferEnd_) 42 | Flush(); 43 | 44 | *current_++ = c; 45 | } 46 | 47 | void PutN(char c, size_t n) { 48 | size_t avail = static_cast(bufferEnd_ - current_); 49 | while (n > avail) { 50 | std::memset(current_, c, avail); 51 | current_ += avail; 52 | Flush(); 53 | n -= avail; 54 | avail = static_cast(bufferEnd_ - current_); 55 | } 56 | 57 | if (n > 0) { 58 | std::memset(current_, c, n); 59 | current_ += n; 60 | } 61 | } 62 | 63 | void Flush() { 64 | if (current_ != buffer_) { 65 | size_t result = fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); 66 | if (result < static_cast(current_ - buffer_)) { 67 | // failure deliberately ignored at this time 68 | // added to avoid warn_unused_result build errors 69 | } 70 | current_ = buffer_; 71 | } 72 | } 73 | 74 | // Not implemented 75 | char Peek() const { RAPIDJSON_ASSERT(false); return 0; } 76 | char Take() { RAPIDJSON_ASSERT(false); return 0; } 77 | size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } 78 | char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 79 | size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } 80 | 81 | private: 82 | // Prohibit copy constructor & assignment operator. 83 | FileWriteStream(const FileWriteStream&); 84 | FileWriteStream& operator=(const FileWriteStream&); 85 | 86 | std::FILE* fp_; 87 | char *buffer_; 88 | char *bufferEnd_; 89 | char *current_; 90 | }; 91 | 92 | //! Implement specialized version of PutN() with memset() for better performance. 93 | template<> 94 | inline void PutN(FileWriteStream& stream, char c, size_t n) { 95 | stream.PutN(c, n); 96 | } 97 | 98 | RAPIDJSON_NAMESPACE_END 99 | 100 | #ifdef __clang__ 101 | RAPIDJSON_DIAG_POP 102 | #endif 103 | 104 | #endif // RAPIDJSON_FILESTREAM_H_ 105 | -------------------------------------------------------------------------------- /3rd_party/include/zipkin/rapidjson/fwd.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_FWD_H_ 16 | #define RAPIDJSON_FWD_H_ 17 | 18 | #include "rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | 22 | // encodings.h 23 | 24 | template struct UTF8; 25 | template struct UTF16; 26 | template struct UTF16BE; 27 | template struct UTF16LE; 28 | template struct UTF32; 29 | template struct UTF32BE; 30 | template struct UTF32LE; 31 | template struct ASCII; 32 | template struct AutoUTF; 33 | 34 | template 35 | struct Transcoder; 36 | 37 | // allocators.h 38 | 39 | class CrtAllocator; 40 | 41 | template 42 | class MemoryPoolAllocator; 43 | 44 | // stream.h 45 | 46 | template 47 | struct GenericStringStream; 48 | 49 | typedef GenericStringStream > StringStream; 50 | 51 | template 52 | struct GenericInsituStringStream; 53 | 54 | typedef GenericInsituStringStream > InsituStringStream; 55 | 56 | // stringbuffer.h 57 | 58 | template 59 | class GenericStringBuffer; 60 | 61 | typedef GenericStringBuffer, CrtAllocator> StringBuffer; 62 | 63 | // filereadstream.h 64 | 65 | class FileReadStream; 66 | 67 | // filewritestream.h 68 | 69 | class FileWriteStream; 70 | 71 | // memorybuffer.h 72 | 73 | template 74 | struct GenericMemoryBuffer; 75 | 76 | typedef GenericMemoryBuffer MemoryBuffer; 77 | 78 | // memorystream.h 79 | 80 | struct MemoryStream; 81 | 82 | // reader.h 83 | 84 | template 85 | struct BaseReaderHandler; 86 | 87 | template 88 | class GenericReader; 89 | 90 | typedef GenericReader, UTF8, CrtAllocator> Reader; 91 | 92 | // writer.h 93 | 94 | template 95 | class Writer; 96 | 97 | // prettywriter.h 98 | 99 | template 100 | class PrettyWriter; 101 | 102 | // document.h 103 | 104 | template 105 | struct GenericMember; 106 | 107 | template 108 | class GenericMemberIterator; 109 | 110 | template 111 | struct GenericStringRef; 112 | 113 | template 114 | class GenericValue; 115 | 116 | typedef GenericValue, MemoryPoolAllocator > Value; 117 | 118 | template 119 | class GenericDocument; 120 | 121 | typedef GenericDocument, MemoryPoolAllocator, CrtAllocator> Document; 122 | 123 | // pointer.h 124 | 125 | template 126 | class GenericPointer; 127 | 128 | typedef GenericPointer Pointer; 129 | 130 | // schema.h 131 | 132 | template 133 | class IGenericRemoteSchemaDocumentProvider; 134 | 135 | template 136 | class GenericSchemaDocument; 137 | 138 | typedef GenericSchemaDocument SchemaDocument; 139 | typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; 140 | 141 | template < 142 | typename SchemaDocumentType, 143 | typename OutputHandler, 144 | typename StateAllocator> 145 | class GenericSchemaValidator; 146 | 147 | typedef GenericSchemaValidator, void>, CrtAllocator> SchemaValidator; 148 | 149 | RAPIDJSON_NAMESPACE_END 150 | 151 | #endif // RAPIDJSON_RAPIDJSONFWD_H_ 152 | -------------------------------------------------------------------------------- /3rd_party/include/zipkin/rapidjson/internal/dtoa.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | // This is a C++ header-only implementation of Grisu2 algorithm from the publication: 16 | // Loitsch, Florian. "Printing floating-point numbers quickly and accurately with 17 | // integers." ACM Sigplan Notices 45.6 (2010): 233-243. 18 | 19 | #ifndef RAPIDJSON_DTOA_ 20 | #define RAPIDJSON_DTOA_ 21 | 22 | #include "itoa.h" // GetDigitsLut() 23 | #include "diyfp.h" 24 | #include "ieee754.h" 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | namespace internal { 28 | 29 | #ifdef __GNUC__ 30 | RAPIDJSON_DIAG_PUSH 31 | RAPIDJSON_DIAG_OFF(effc++) 32 | RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124 33 | #endif 34 | 35 | inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { 36 | while (rest < wp_w && delta - rest >= ten_kappa && 37 | (rest + ten_kappa < wp_w || /// closer 38 | wp_w - rest > rest + ten_kappa - wp_w)) { 39 | buffer[len - 1]--; 40 | rest += ten_kappa; 41 | } 42 | } 43 | 44 | inline int CountDecimalDigit32(uint32_t n) { 45 | // Simple pure C++ implementation was faster than __builtin_clz version in this situation. 46 | if (n < 10) return 1; 47 | if (n < 100) return 2; 48 | if (n < 1000) return 3; 49 | if (n < 10000) return 4; 50 | if (n < 100000) return 5; 51 | if (n < 1000000) return 6; 52 | if (n < 10000000) return 7; 53 | if (n < 100000000) return 8; 54 | // Will not reach 10 digits in DigitGen() 55 | //if (n < 1000000000) return 9; 56 | //return 10; 57 | return 9; 58 | } 59 | 60 | inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { 61 | static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; 62 | const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); 63 | const DiyFp wp_w = Mp - W; 64 | uint32_t p1 = static_cast(Mp.f >> -one.e); 65 | uint64_t p2 = Mp.f & (one.f - 1); 66 | int kappa = CountDecimalDigit32(p1); // kappa in [0, 9] 67 | *len = 0; 68 | 69 | while (kappa > 0) { 70 | uint32_t d = 0; 71 | switch (kappa) { 72 | case 9: d = p1 / 100000000; p1 %= 100000000; break; 73 | case 8: d = p1 / 10000000; p1 %= 10000000; break; 74 | case 7: d = p1 / 1000000; p1 %= 1000000; break; 75 | case 6: d = p1 / 100000; p1 %= 100000; break; 76 | case 5: d = p1 / 10000; p1 %= 10000; break; 77 | case 4: d = p1 / 1000; p1 %= 1000; break; 78 | case 3: d = p1 / 100; p1 %= 100; break; 79 | case 2: d = p1 / 10; p1 %= 10; break; 80 | case 1: d = p1; p1 = 0; break; 81 | default:; 82 | } 83 | if (d || *len) 84 | buffer[(*len)++] = static_cast('0' + static_cast(d)); 85 | kappa--; 86 | uint64_t tmp = (static_cast(p1) << -one.e) + p2; 87 | if (tmp <= delta) { 88 | *K += kappa; 89 | GrisuRound(buffer, *len, delta, tmp, static_cast(kPow10[kappa]) << -one.e, wp_w.f); 90 | return; 91 | } 92 | } 93 | 94 | // kappa = 0 95 | for (;;) { 96 | p2 *= 10; 97 | delta *= 10; 98 | char d = static_cast(p2 >> -one.e); 99 | if (d || *len) 100 | buffer[(*len)++] = static_cast('0' + d); 101 | p2 &= one.f - 1; 102 | kappa--; 103 | if (p2 < delta) { 104 | *K += kappa; 105 | int index = -kappa; 106 | GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[index] : 0)); 107 | return; 108 | } 109 | } 110 | } 111 | 112 | inline void Grisu2(double value, char* buffer, int* length, int* K) { 113 | const DiyFp v(value); 114 | DiyFp w_m, w_p; 115 | v.NormalizedBoundaries(&w_m, &w_p); 116 | 117 | const DiyFp c_mk = GetCachedPower(w_p.e, K); 118 | const DiyFp W = v.Normalize() * c_mk; 119 | DiyFp Wp = w_p * c_mk; 120 | DiyFp Wm = w_m * c_mk; 121 | Wm.f++; 122 | Wp.f--; 123 | DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K); 124 | } 125 | 126 | inline char* WriteExponent(int K, char* buffer) { 127 | if (K < 0) { 128 | *buffer++ = '-'; 129 | K = -K; 130 | } 131 | 132 | if (K >= 100) { 133 | *buffer++ = static_cast('0' + static_cast(K / 100)); 134 | K %= 100; 135 | const char* d = GetDigitsLut() + K * 2; 136 | *buffer++ = d[0]; 137 | *buffer++ = d[1]; 138 | } 139 | else if (K >= 10) { 140 | const char* d = GetDigitsLut() + K * 2; 141 | *buffer++ = d[0]; 142 | *buffer++ = d[1]; 143 | } 144 | else 145 | *buffer++ = static_cast('0' + static_cast(K)); 146 | 147 | return buffer; 148 | } 149 | 150 | inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) { 151 | const int kk = length + k; // 10^(kk-1) <= v < 10^kk 152 | 153 | if (0 <= k && kk <= 21) { 154 | // 1234e7 -> 12340000000 155 | for (int i = length; i < kk; i++) 156 | buffer[i] = '0'; 157 | buffer[kk] = '.'; 158 | buffer[kk + 1] = '0'; 159 | return &buffer[kk + 2]; 160 | } 161 | else if (0 < kk && kk <= 21) { 162 | // 1234e-2 -> 12.34 163 | std::memmove(&buffer[kk + 1], &buffer[kk], static_cast(length - kk)); 164 | buffer[kk] = '.'; 165 | if (0 > k + maxDecimalPlaces) { 166 | // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1 167 | // Remove extra trailing zeros (at least one) after truncation. 168 | for (int i = kk + maxDecimalPlaces; i > kk + 1; i--) 169 | if (buffer[i] != '0') 170 | return &buffer[i + 1]; 171 | return &buffer[kk + 2]; // Reserve one zero 172 | } 173 | else 174 | return &buffer[length + 1]; 175 | } 176 | else if (-6 < kk && kk <= 0) { 177 | // 1234e-6 -> 0.001234 178 | const int offset = 2 - kk; 179 | std::memmove(&buffer[offset], &buffer[0], static_cast(length)); 180 | buffer[0] = '0'; 181 | buffer[1] = '.'; 182 | for (int i = 2; i < offset; i++) 183 | buffer[i] = '0'; 184 | if (length - kk > maxDecimalPlaces) { 185 | // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1 186 | // Remove extra trailing zeros (at least one) after truncation. 187 | for (int i = maxDecimalPlaces + 1; i > 2; i--) 188 | if (buffer[i] != '0') 189 | return &buffer[i + 1]; 190 | return &buffer[3]; // Reserve one zero 191 | } 192 | else 193 | return &buffer[length + offset]; 194 | } 195 | else if (kk < -maxDecimalPlaces) { 196 | // Truncate to zero 197 | buffer[0] = '0'; 198 | buffer[1] = '.'; 199 | buffer[2] = '0'; 200 | return &buffer[3]; 201 | } 202 | else if (length == 1) { 203 | // 1e30 204 | buffer[1] = 'e'; 205 | return WriteExponent(kk - 1, &buffer[2]); 206 | } 207 | else { 208 | // 1234e30 -> 1.234e33 209 | std::memmove(&buffer[2], &buffer[1], static_cast(length - 1)); 210 | buffer[1] = '.'; 211 | buffer[length + 1] = 'e'; 212 | return WriteExponent(kk - 1, &buffer[0 + length + 2]); 213 | } 214 | } 215 | 216 | inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) { 217 | RAPIDJSON_ASSERT(maxDecimalPlaces >= 1); 218 | Double d(value); 219 | if (d.IsZero()) { 220 | if (d.Sign()) 221 | *buffer++ = '-'; // -0.0, Issue #289 222 | buffer[0] = '0'; 223 | buffer[1] = '.'; 224 | buffer[2] = '0'; 225 | return &buffer[3]; 226 | } 227 | else { 228 | if (value < 0) { 229 | *buffer++ = '-'; 230 | value = -value; 231 | } 232 | int length, K; 233 | Grisu2(value, buffer, &length, &K); 234 | return Prettify(buffer, length, K, maxDecimalPlaces); 235 | } 236 | } 237 | 238 | #ifdef __GNUC__ 239 | RAPIDJSON_DIAG_POP 240 | #endif 241 | 242 | } // namespace internal 243 | RAPIDJSON_NAMESPACE_END 244 | 245 | #endif // RAPIDJSON_DTOA_ 246 | -------------------------------------------------------------------------------- /3rd_party/include/zipkin/rapidjson/internal/ieee754.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_IEEE754_ 16 | #define RAPIDJSON_IEEE754_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | namespace internal { 22 | 23 | class Double { 24 | public: 25 | Double() {} 26 | Double(double d) : d_(d) {} 27 | Double(uint64_t u) : u_(u) {} 28 | 29 | double Value() const { return d_; } 30 | uint64_t Uint64Value() const { return u_; } 31 | 32 | double NextPositiveDouble() const { 33 | RAPIDJSON_ASSERT(!Sign()); 34 | return Double(u_ + 1).Value(); 35 | } 36 | 37 | bool Sign() const { return (u_ & kSignMask) != 0; } 38 | uint64_t Significand() const { return u_ & kSignificandMask; } 39 | int Exponent() const { return static_cast(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); } 40 | 41 | bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } 42 | bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } 43 | bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; } 44 | bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } 45 | bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } 46 | 47 | uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } 48 | int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } 49 | uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } 50 | 51 | static int EffectiveSignificandSize(int order) { 52 | if (order >= -1021) 53 | return 53; 54 | else if (order <= -1074) 55 | return 0; 56 | else 57 | return order + 1074; 58 | } 59 | 60 | private: 61 | static const int kSignificandSize = 52; 62 | static const int kExponentBias = 0x3FF; 63 | static const int kDenormalExponent = 1 - kExponentBias; 64 | static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000); 65 | static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); 66 | static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); 67 | static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); 68 | 69 | union { 70 | double d_; 71 | uint64_t u_; 72 | }; 73 | }; 74 | 75 | } // namespace internal 76 | RAPIDJSON_NAMESPACE_END 77 | 78 | #endif // RAPIDJSON_IEEE754_ 79 | -------------------------------------------------------------------------------- /3rd_party/include/zipkin/rapidjson/internal/meta.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_META_H_ 16 | #define RAPIDJSON_INTERNAL_META_H_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | #ifdef __GNUC__ 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(effc++) 23 | #endif 24 | #if defined(_MSC_VER) 25 | RAPIDJSON_DIAG_PUSH 26 | RAPIDJSON_DIAG_OFF(6334) 27 | #endif 28 | 29 | #if RAPIDJSON_HAS_CXX11_TYPETRAITS 30 | #include 31 | #endif 32 | 33 | //@cond RAPIDJSON_INTERNAL 34 | RAPIDJSON_NAMESPACE_BEGIN 35 | namespace internal { 36 | 37 | // Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching 38 | template struct Void { typedef void Type; }; 39 | 40 | /////////////////////////////////////////////////////////////////////////////// 41 | // BoolType, TrueType, FalseType 42 | // 43 | template struct BoolType { 44 | static const bool Value = Cond; 45 | typedef BoolType Type; 46 | }; 47 | typedef BoolType TrueType; 48 | typedef BoolType FalseType; 49 | 50 | 51 | /////////////////////////////////////////////////////////////////////////////// 52 | // SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr 53 | // 54 | 55 | template struct SelectIfImpl { template struct Apply { typedef T1 Type; }; }; 56 | template <> struct SelectIfImpl { template struct Apply { typedef T2 Type; }; }; 57 | template struct SelectIfCond : SelectIfImpl::template Apply {}; 58 | template struct SelectIf : SelectIfCond {}; 59 | 60 | template struct AndExprCond : FalseType {}; 61 | template <> struct AndExprCond : TrueType {}; 62 | template struct OrExprCond : TrueType {}; 63 | template <> struct OrExprCond : FalseType {}; 64 | 65 | template struct BoolExpr : SelectIf::Type {}; 66 | template struct NotExpr : SelectIf::Type {}; 67 | template struct AndExpr : AndExprCond::Type {}; 68 | template struct OrExpr : OrExprCond::Type {}; 69 | 70 | 71 | /////////////////////////////////////////////////////////////////////////////// 72 | // AddConst, MaybeAddConst, RemoveConst 73 | template struct AddConst { typedef const T Type; }; 74 | template struct MaybeAddConst : SelectIfCond {}; 75 | template struct RemoveConst { typedef T Type; }; 76 | template struct RemoveConst { typedef T Type; }; 77 | 78 | 79 | /////////////////////////////////////////////////////////////////////////////// 80 | // IsSame, IsConst, IsMoreConst, IsPointer 81 | // 82 | template struct IsSame : FalseType {}; 83 | template struct IsSame : TrueType {}; 84 | 85 | template struct IsConst : FalseType {}; 86 | template struct IsConst : TrueType {}; 87 | 88 | template 89 | struct IsMoreConst 90 | : AndExpr::Type, typename RemoveConst::Type>, 91 | BoolType::Value >= IsConst::Value> >::Type {}; 92 | 93 | template struct IsPointer : FalseType {}; 94 | template struct IsPointer : TrueType {}; 95 | 96 | /////////////////////////////////////////////////////////////////////////////// 97 | // IsBaseOf 98 | // 99 | #if RAPIDJSON_HAS_CXX11_TYPETRAITS 100 | 101 | template struct IsBaseOf 102 | : BoolType< ::std::is_base_of::value> {}; 103 | 104 | #else // simplified version adopted from Boost 105 | 106 | template struct IsBaseOfImpl { 107 | RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0); 108 | RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0); 109 | 110 | typedef char (&Yes)[1]; 111 | typedef char (&No) [2]; 112 | 113 | template 114 | static Yes Check(const D*, T); 115 | static No Check(const B*, int); 116 | 117 | struct Host { 118 | operator const B*() const; 119 | operator const D*(); 120 | }; 121 | 122 | enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) }; 123 | }; 124 | 125 | template struct IsBaseOf 126 | : OrExpr, BoolExpr > >::Type {}; 127 | 128 | #endif // RAPIDJSON_HAS_CXX11_TYPETRAITS 129 | 130 | 131 | ////////////////////////////////////////////////////////////////////////// 132 | // EnableIf / DisableIf 133 | // 134 | template struct EnableIfCond { typedef T Type; }; 135 | template struct EnableIfCond { /* empty */ }; 136 | 137 | template struct DisableIfCond { typedef T Type; }; 138 | template struct DisableIfCond { /* empty */ }; 139 | 140 | template 141 | struct EnableIf : EnableIfCond {}; 142 | 143 | template 144 | struct DisableIf : DisableIfCond {}; 145 | 146 | // SFINAE helpers 147 | struct SfinaeTag {}; 148 | template struct RemoveSfinaeTag; 149 | template struct RemoveSfinaeTag { typedef T Type; }; 150 | 151 | #define RAPIDJSON_REMOVEFPTR_(type) \ 152 | typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \ 153 | < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type 154 | 155 | #define RAPIDJSON_ENABLEIF(cond) \ 156 | typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ 157 | ::Type * = NULL 158 | 159 | #define RAPIDJSON_DISABLEIF(cond) \ 160 | typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ 161 | ::Type * = NULL 162 | 163 | #define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \ 164 | typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ 165 | ::Type 167 | 168 | #define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ 169 | typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ 170 | ::Type 172 | 173 | } // namespace internal 174 | RAPIDJSON_NAMESPACE_END 175 | //@endcond 176 | 177 | #if defined(__GNUC__) || defined(_MSC_VER) 178 | RAPIDJSON_DIAG_POP 179 | #endif 180 | 181 | #endif // RAPIDJSON_INTERNAL_META_H_ 182 | -------------------------------------------------------------------------------- /3rd_party/include/zipkin/rapidjson/internal/pow10.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_POW10_ 16 | #define RAPIDJSON_POW10_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | namespace internal { 22 | 23 | //! Computes integer powers of 10 in double (10.0^n). 24 | /*! This function uses lookup table for fast and accurate results. 25 | \param n non-negative exponent. Must <= 308. 26 | \return 10.0^n 27 | */ 28 | inline double Pow10(int n) { 29 | static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes 30 | 1e+0, 31 | 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, 32 | 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, 33 | 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, 34 | 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, 35 | 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100, 36 | 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120, 37 | 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140, 38 | 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160, 39 | 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180, 40 | 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200, 41 | 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220, 42 | 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240, 43 | 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260, 44 | 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280, 45 | 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300, 46 | 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 47 | }; 48 | RAPIDJSON_ASSERT(n >= 0 && n <= 308); 49 | return e[n]; 50 | } 51 | 52 | } // namespace internal 53 | RAPIDJSON_NAMESPACE_END 54 | 55 | #endif // RAPIDJSON_POW10_ 56 | -------------------------------------------------------------------------------- /3rd_party/include/zipkin/rapidjson/internal/stack.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_STACK_H_ 16 | #define RAPIDJSON_INTERNAL_STACK_H_ 17 | 18 | #include "../allocators.h" 19 | #include "swap.h" 20 | 21 | #if defined(__clang__) 22 | RAPIDJSON_DIAG_PUSH 23 | RAPIDJSON_DIAG_OFF(c++98-compat) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | namespace internal { 28 | 29 | /////////////////////////////////////////////////////////////////////////////// 30 | // Stack 31 | 32 | //! A type-unsafe stack for storing different types of data. 33 | /*! \tparam Allocator Allocator for allocating stack memory. 34 | */ 35 | template 36 | class Stack { 37 | public: 38 | // Optimization note: Do not allocate memory for stack_ in constructor. 39 | // Do it lazily when first Push() -> Expand() -> Resize(). 40 | Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) { 41 | } 42 | 43 | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 44 | Stack(Stack&& rhs) 45 | : allocator_(rhs.allocator_), 46 | ownAllocator_(rhs.ownAllocator_), 47 | stack_(rhs.stack_), 48 | stackTop_(rhs.stackTop_), 49 | stackEnd_(rhs.stackEnd_), 50 | initialCapacity_(rhs.initialCapacity_) 51 | { 52 | rhs.allocator_ = 0; 53 | rhs.ownAllocator_ = 0; 54 | rhs.stack_ = 0; 55 | rhs.stackTop_ = 0; 56 | rhs.stackEnd_ = 0; 57 | rhs.initialCapacity_ = 0; 58 | } 59 | #endif 60 | 61 | ~Stack() { 62 | Destroy(); 63 | } 64 | 65 | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 66 | Stack& operator=(Stack&& rhs) { 67 | if (&rhs != this) 68 | { 69 | Destroy(); 70 | 71 | allocator_ = rhs.allocator_; 72 | ownAllocator_ = rhs.ownAllocator_; 73 | stack_ = rhs.stack_; 74 | stackTop_ = rhs.stackTop_; 75 | stackEnd_ = rhs.stackEnd_; 76 | initialCapacity_ = rhs.initialCapacity_; 77 | 78 | rhs.allocator_ = 0; 79 | rhs.ownAllocator_ = 0; 80 | rhs.stack_ = 0; 81 | rhs.stackTop_ = 0; 82 | rhs.stackEnd_ = 0; 83 | rhs.initialCapacity_ = 0; 84 | } 85 | return *this; 86 | } 87 | #endif 88 | 89 | void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT { 90 | internal::Swap(allocator_, rhs.allocator_); 91 | internal::Swap(ownAllocator_, rhs.ownAllocator_); 92 | internal::Swap(stack_, rhs.stack_); 93 | internal::Swap(stackTop_, rhs.stackTop_); 94 | internal::Swap(stackEnd_, rhs.stackEnd_); 95 | internal::Swap(initialCapacity_, rhs.initialCapacity_); 96 | } 97 | 98 | void Clear() { stackTop_ = stack_; } 99 | 100 | void ShrinkToFit() { 101 | if (Empty()) { 102 | // If the stack is empty, completely deallocate the memory. 103 | Allocator::Free(stack_); 104 | stack_ = 0; 105 | stackTop_ = 0; 106 | stackEnd_ = 0; 107 | } 108 | else 109 | Resize(GetSize()); 110 | } 111 | 112 | // Optimization note: try to minimize the size of this function for force inline. 113 | // Expansion is run very infrequently, so it is moved to another (probably non-inline) function. 114 | template 115 | RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) { 116 | // Expand the stack if needed 117 | if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_)) 118 | Expand(count); 119 | } 120 | 121 | template 122 | RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { 123 | Reserve(count); 124 | return PushUnsafe(count); 125 | } 126 | 127 | template 128 | RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) { 129 | RAPIDJSON_ASSERT(stackTop_); 130 | RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_); 131 | T* ret = reinterpret_cast(stackTop_); 132 | stackTop_ += sizeof(T) * count; 133 | return ret; 134 | } 135 | 136 | template 137 | T* Pop(size_t count) { 138 | RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); 139 | stackTop_ -= count * sizeof(T); 140 | return reinterpret_cast(stackTop_); 141 | } 142 | 143 | template 144 | T* Top() { 145 | RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); 146 | return reinterpret_cast(stackTop_ - sizeof(T)); 147 | } 148 | 149 | template 150 | const T* Top() const { 151 | RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); 152 | return reinterpret_cast(stackTop_ - sizeof(T)); 153 | } 154 | 155 | template 156 | T* End() { return reinterpret_cast(stackTop_); } 157 | 158 | template 159 | const T* End() const { return reinterpret_cast(stackTop_); } 160 | 161 | template 162 | T* Bottom() { return reinterpret_cast(stack_); } 163 | 164 | template 165 | const T* Bottom() const { return reinterpret_cast(stack_); } 166 | 167 | bool HasAllocator() const { 168 | return allocator_ != 0; 169 | } 170 | 171 | Allocator& GetAllocator() { 172 | RAPIDJSON_ASSERT(allocator_); 173 | return *allocator_; 174 | } 175 | 176 | bool Empty() const { return stackTop_ == stack_; } 177 | size_t GetSize() const { return static_cast(stackTop_ - stack_); } 178 | size_t GetCapacity() const { return static_cast(stackEnd_ - stack_); } 179 | 180 | private: 181 | template 182 | void Expand(size_t count) { 183 | // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity. 184 | size_t newCapacity; 185 | if (stack_ == 0) { 186 | if (!allocator_) 187 | ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); 188 | newCapacity = initialCapacity_; 189 | } else { 190 | newCapacity = GetCapacity(); 191 | newCapacity += (newCapacity + 1) / 2; 192 | } 193 | size_t newSize = GetSize() + sizeof(T) * count; 194 | if (newCapacity < newSize) 195 | newCapacity = newSize; 196 | 197 | Resize(newCapacity); 198 | } 199 | 200 | void Resize(size_t newCapacity) { 201 | const size_t size = GetSize(); // Backup the current size 202 | stack_ = static_cast(allocator_->Realloc(stack_, GetCapacity(), newCapacity)); 203 | stackTop_ = stack_ + size; 204 | stackEnd_ = stack_ + newCapacity; 205 | } 206 | 207 | void Destroy() { 208 | Allocator::Free(stack_); 209 | RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack 210 | } 211 | 212 | // Prohibit copy constructor & assignment operator. 213 | Stack(const Stack&); 214 | Stack& operator=(const Stack&); 215 | 216 | Allocator* allocator_; 217 | Allocator* ownAllocator_; 218 | char *stack_; 219 | char *stackTop_; 220 | char *stackEnd_; 221 | size_t initialCapacity_; 222 | }; 223 | 224 | } // namespace internal 225 | RAPIDJSON_NAMESPACE_END 226 | 227 | #if defined(__clang__) 228 | RAPIDJSON_DIAG_POP 229 | #endif 230 | 231 | #endif // RAPIDJSON_STACK_H_ 232 | -------------------------------------------------------------------------------- /3rd_party/include/zipkin/rapidjson/internal/strfunc.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ 16 | #define RAPIDJSON_INTERNAL_STRFUNC_H_ 17 | 18 | #include "../stream.h" 19 | #include 20 | 21 | RAPIDJSON_NAMESPACE_BEGIN 22 | namespace internal { 23 | 24 | //! Custom strlen() which works on different character types. 25 | /*! \tparam Ch Character type (e.g. char, wchar_t, short) 26 | \param s Null-terminated input string. 27 | \return Number of characters in the string. 28 | \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. 29 | */ 30 | template 31 | inline SizeType StrLen(const Ch* s) { 32 | RAPIDJSON_ASSERT(s != 0); 33 | const Ch* p = s; 34 | while (*p) ++p; 35 | return SizeType(p - s); 36 | } 37 | 38 | template <> 39 | inline SizeType StrLen(const char* s) { 40 | return SizeType(std::strlen(s)); 41 | } 42 | 43 | template <> 44 | inline SizeType StrLen(const wchar_t* s) { 45 | return SizeType(std::wcslen(s)); 46 | } 47 | 48 | //! Returns number of code points in a encoded string. 49 | template 50 | bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { 51 | RAPIDJSON_ASSERT(s != 0); 52 | RAPIDJSON_ASSERT(outCount != 0); 53 | GenericStringStream is(s); 54 | const typename Encoding::Ch* end = s + length; 55 | SizeType count = 0; 56 | while (is.src_ < end) { 57 | unsigned codepoint; 58 | if (!Encoding::Decode(is, &codepoint)) 59 | return false; 60 | count++; 61 | } 62 | *outCount = count; 63 | return true; 64 | } 65 | 66 | } // namespace internal 67 | RAPIDJSON_NAMESPACE_END 68 | 69 | #endif // RAPIDJSON_INTERNAL_STRFUNC_H_ 70 | -------------------------------------------------------------------------------- /3rd_party/include/zipkin/rapidjson/internal/strtod.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_STRTOD_ 16 | #define RAPIDJSON_STRTOD_ 17 | 18 | #include "ieee754.h" 19 | #include "biginteger.h" 20 | #include "diyfp.h" 21 | #include "pow10.h" 22 | 23 | RAPIDJSON_NAMESPACE_BEGIN 24 | namespace internal { 25 | 26 | inline double FastPath(double significand, int exp) { 27 | if (exp < -308) 28 | return 0.0; 29 | else if (exp >= 0) 30 | return significand * internal::Pow10(exp); 31 | else 32 | return significand / internal::Pow10(-exp); 33 | } 34 | 35 | inline double StrtodNormalPrecision(double d, int p) { 36 | if (p < -308) { 37 | // Prevent expSum < -308, making Pow10(p) = 0 38 | d = FastPath(d, -308); 39 | d = FastPath(d, p + 308); 40 | } 41 | else 42 | d = FastPath(d, p); 43 | return d; 44 | } 45 | 46 | template 47 | inline T Min3(T a, T b, T c) { 48 | T m = a; 49 | if (m > b) m = b; 50 | if (m > c) m = c; 51 | return m; 52 | } 53 | 54 | inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) { 55 | const Double db(b); 56 | const uint64_t bInt = db.IntegerSignificand(); 57 | const int bExp = db.IntegerExponent(); 58 | const int hExp = bExp - 1; 59 | 60 | int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0; 61 | 62 | // Adjust for decimal exponent 63 | if (dExp >= 0) { 64 | dS_Exp2 += dExp; 65 | dS_Exp5 += dExp; 66 | } 67 | else { 68 | bS_Exp2 -= dExp; 69 | bS_Exp5 -= dExp; 70 | hS_Exp2 -= dExp; 71 | hS_Exp5 -= dExp; 72 | } 73 | 74 | // Adjust for binary exponent 75 | if (bExp >= 0) 76 | bS_Exp2 += bExp; 77 | else { 78 | dS_Exp2 -= bExp; 79 | hS_Exp2 -= bExp; 80 | } 81 | 82 | // Adjust for half ulp exponent 83 | if (hExp >= 0) 84 | hS_Exp2 += hExp; 85 | else { 86 | dS_Exp2 -= hExp; 87 | bS_Exp2 -= hExp; 88 | } 89 | 90 | // Remove common power of two factor from all three scaled values 91 | int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2); 92 | dS_Exp2 -= common_Exp2; 93 | bS_Exp2 -= common_Exp2; 94 | hS_Exp2 -= common_Exp2; 95 | 96 | BigInteger dS = d; 97 | dS.MultiplyPow5(static_cast(dS_Exp5)) <<= static_cast(dS_Exp2); 98 | 99 | BigInteger bS(bInt); 100 | bS.MultiplyPow5(static_cast(bS_Exp5)) <<= static_cast(bS_Exp2); 101 | 102 | BigInteger hS(1); 103 | hS.MultiplyPow5(static_cast(hS_Exp5)) <<= static_cast(hS_Exp2); 104 | 105 | BigInteger delta(0); 106 | dS.Difference(bS, &delta); 107 | 108 | return delta.Compare(hS); 109 | } 110 | 111 | inline bool StrtodFast(double d, int p, double* result) { 112 | // Use fast path for string-to-double conversion if possible 113 | // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ 114 | if (p > 22 && p < 22 + 16) { 115 | // Fast Path Cases In Disguise 116 | d *= internal::Pow10(p - 22); 117 | p = 22; 118 | } 119 | 120 | if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1 121 | *result = FastPath(d, p); 122 | return true; 123 | } 124 | else 125 | return false; 126 | } 127 | 128 | // Compute an approximation and see if it is within 1/2 ULP 129 | inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) { 130 | uint64_t significand = 0; 131 | size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999 132 | for (; i < length; i++) { 133 | if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || 134 | (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5')) 135 | break; 136 | significand = significand * 10u + static_cast(decimals[i] - '0'); 137 | } 138 | 139 | if (i < length && decimals[i] >= '5') // Rounding 140 | significand++; 141 | 142 | size_t remaining = length - i; 143 | const int kUlpShift = 3; 144 | const int kUlp = 1 << kUlpShift; 145 | int64_t error = (remaining == 0) ? 0 : kUlp / 2; 146 | 147 | DiyFp v(significand, 0); 148 | v = v.Normalize(); 149 | error <<= -v.e; 150 | 151 | const int dExp = static_cast(decimalPosition) - static_cast(i) + exp; 152 | 153 | int actualExp; 154 | DiyFp cachedPower = GetCachedPower10(dExp, &actualExp); 155 | if (actualExp != dExp) { 156 | static const DiyFp kPow10[] = { 157 | DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1 158 | DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2 159 | DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3 160 | DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4 161 | DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5 162 | DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6 163 | DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7 164 | }; 165 | int adjustment = dExp - actualExp - 1; 166 | RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7); 167 | v = v * kPow10[adjustment]; 168 | if (length + static_cast(adjustment)> 19u) // has more digits than decimal digits in 64-bit 169 | error += kUlp / 2; 170 | } 171 | 172 | v = v * cachedPower; 173 | 174 | error += kUlp + (error == 0 ? 0 : 1); 175 | 176 | const int oldExp = v.e; 177 | v = v.Normalize(); 178 | error <<= oldExp - v.e; 179 | 180 | const int effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); 181 | int precisionSize = 64 - effectiveSignificandSize; 182 | if (precisionSize + kUlpShift >= 64) { 183 | int scaleExp = (precisionSize + kUlpShift) - 63; 184 | v.f >>= scaleExp; 185 | v.e += scaleExp; 186 | error = (error >> scaleExp) + 1 + kUlp; 187 | precisionSize -= scaleExp; 188 | } 189 | 190 | DiyFp rounded(v.f >> precisionSize, v.e + precisionSize); 191 | const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; 192 | const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp; 193 | if (precisionBits >= halfWay + static_cast(error)) { 194 | rounded.f++; 195 | if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340) 196 | rounded.f >>= 1; 197 | rounded.e++; 198 | } 199 | } 200 | 201 | *result = rounded.ToDouble(); 202 | 203 | return halfWay - static_cast(error) >= precisionBits || precisionBits >= halfWay + static_cast(error); 204 | } 205 | 206 | inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) { 207 | const BigInteger dInt(decimals, length); 208 | const int dExp = static_cast(decimalPosition) - static_cast(length) + exp; 209 | Double a(approx); 210 | int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp); 211 | if (cmp < 0) 212 | return a.Value(); // within half ULP 213 | else if (cmp == 0) { 214 | // Round towards even 215 | if (a.Significand() & 1) 216 | return a.NextPositiveDouble(); 217 | else 218 | return a.Value(); 219 | } 220 | else // adjustment 221 | return a.NextPositiveDouble(); 222 | } 223 | 224 | inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) { 225 | RAPIDJSON_ASSERT(d >= 0.0); 226 | RAPIDJSON_ASSERT(length >= 1); 227 | 228 | double result; 229 | if (StrtodFast(d, p, &result)) 230 | return result; 231 | 232 | // Trim leading zeros 233 | while (*decimals == '0' && length > 1) { 234 | length--; 235 | decimals++; 236 | decimalPosition--; 237 | } 238 | 239 | // Trim trailing zeros 240 | while (decimals[length - 1] == '0' && length > 1) { 241 | length--; 242 | decimalPosition--; 243 | exp++; 244 | } 245 | 246 | // Trim right-most digits 247 | const int kMaxDecimalDigit = 780; 248 | if (static_cast(length) > kMaxDecimalDigit) { 249 | int delta = (static_cast(length) - kMaxDecimalDigit); 250 | exp += delta; 251 | decimalPosition -= static_cast(delta); 252 | length = kMaxDecimalDigit; 253 | } 254 | 255 | // If too small, underflow to zero 256 | if (int(length) + exp < -324) 257 | return 0.0; 258 | 259 | if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result)) 260 | return result; 261 | 262 | // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison 263 | return StrtodBigInteger(result, decimals, length, decimalPosition, exp); 264 | } 265 | 266 | } // namespace internal 267 | RAPIDJSON_NAMESPACE_END 268 | 269 | #endif // RAPIDJSON_STRTOD_ 270 | -------------------------------------------------------------------------------- /3rd_party/include/zipkin/rapidjson/internal/swap.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_SWAP_H_ 16 | #define RAPIDJSON_INTERNAL_SWAP_H_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | #if defined(__clang__) 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(c++98-compat) 23 | #endif 24 | 25 | RAPIDJSON_NAMESPACE_BEGIN 26 | namespace internal { 27 | 28 | //! Custom swap() to avoid dependency on C++ header 29 | /*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only. 30 | \note This has the same semantics as std::swap(). 31 | */ 32 | template 33 | inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT { 34 | T tmp = a; 35 | a = b; 36 | b = tmp; 37 | } 38 | 39 | } // namespace internal 40 | RAPIDJSON_NAMESPACE_END 41 | 42 | #if defined(__clang__) 43 | RAPIDJSON_DIAG_POP 44 | #endif 45 | 46 | #endif // RAPIDJSON_INTERNAL_SWAP_H_ 47 | -------------------------------------------------------------------------------- /3rd_party/include/zipkin/rapidjson/istreamwrapper.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_ISTREAMWRAPPER_H_ 16 | #define RAPIDJSON_ISTREAMWRAPPER_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | 21 | #ifdef __clang__ 22 | RAPIDJSON_DIAG_PUSH 23 | RAPIDJSON_DIAG_OFF(padded) 24 | #endif 25 | 26 | #ifdef _MSC_VER 27 | RAPIDJSON_DIAG_PUSH 28 | RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized 29 | #endif 30 | 31 | RAPIDJSON_NAMESPACE_BEGIN 32 | 33 | //! Wrapper of \c std::basic_istream into RapidJSON's Stream concept. 34 | /*! 35 | The classes can be wrapped including but not limited to: 36 | 37 | - \c std::istringstream 38 | - \c std::stringstream 39 | - \c std::wistringstream 40 | - \c std::wstringstream 41 | - \c std::ifstream 42 | - \c std::fstream 43 | - \c std::wifstream 44 | - \c std::wfstream 45 | 46 | \tparam StreamType Class derived from \c std::basic_istream. 47 | */ 48 | 49 | template 50 | class BasicIStreamWrapper { 51 | public: 52 | typedef typename StreamType::char_type Ch; 53 | BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {} 54 | 55 | Ch Peek() const { 56 | typename StreamType::int_type c = stream_.peek(); 57 | return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast(c) : static_cast('\0'); 58 | } 59 | 60 | Ch Take() { 61 | typename StreamType::int_type c = stream_.get(); 62 | if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) { 63 | count_++; 64 | return static_cast(c); 65 | } 66 | else 67 | return '\0'; 68 | } 69 | 70 | // tellg() may return -1 when failed. So we count by ourself. 71 | size_t Tell() const { return count_; } 72 | 73 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 74 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 75 | void Flush() { RAPIDJSON_ASSERT(false); } 76 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 77 | 78 | // For encoding detection only. 79 | const Ch* Peek4() const { 80 | RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream. 81 | int i; 82 | bool hasError = false; 83 | for (i = 0; i < 4; ++i) { 84 | typename StreamType::int_type c = stream_.get(); 85 | if (c == StreamType::traits_type::eof()) { 86 | hasError = true; 87 | stream_.clear(); 88 | break; 89 | } 90 | peekBuffer_[i] = static_cast(c); 91 | } 92 | for (--i; i >= 0; --i) 93 | stream_.putback(peekBuffer_[i]); 94 | return !hasError ? peekBuffer_ : 0; 95 | } 96 | 97 | private: 98 | BasicIStreamWrapper(const BasicIStreamWrapper&); 99 | BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); 100 | 101 | StreamType& stream_; 102 | size_t count_; //!< Number of characters read. Note: 103 | mutable Ch peekBuffer_[4]; 104 | }; 105 | 106 | typedef BasicIStreamWrapper IStreamWrapper; 107 | typedef BasicIStreamWrapper WIStreamWrapper; 108 | 109 | #if defined(__clang__) || defined(_MSC_VER) 110 | RAPIDJSON_DIAG_POP 111 | #endif 112 | 113 | RAPIDJSON_NAMESPACE_END 114 | 115 | #endif // RAPIDJSON_ISTREAMWRAPPER_H_ 116 | -------------------------------------------------------------------------------- /3rd_party/include/zipkin/rapidjson/license.txt: -------------------------------------------------------------------------------- 1 | Tencent is pleased to support the open source community by making RapidJSON available. 2 | 3 | Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | 5 | If you have downloaded a copy of the RapidJSON binary from Tencent, please note that the RapidJSON binary is licensed under the MIT License. 6 | If you have downloaded a copy of the RapidJSON source code from Tencent, please note that RapidJSON source code is licensed under the MIT License, except for the third-party components listed below which are subject to different license terms. Your integration of RapidJSON into your own projects may require compliance with the MIT License, as well as the other licenses applicable to the third-party components included within RapidJSON. To avoid the problematic JSON license in your own projects, it's sufficient to exclude the bin/jsonchecker/ directory, as it's the only code under the JSON license. 7 | A copy of the MIT License is included in this file. 8 | 9 | Other dependencies and licenses: 10 | 11 | Open Source Software Licensed Under the BSD License: 12 | -------------------------------------------------------------------- 13 | 14 | The msinttypes r29 15 | Copyright (c) 2006-2013 Alexander Chemeris 16 | All rights reserved. 17 | 18 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 19 | 20 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 21 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 22 | * Neither the name of copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | Open Source Software Licensed Under the JSON License: 27 | -------------------------------------------------------------------- 28 | 29 | json.org 30 | Copyright (c) 2002 JSON.org 31 | All Rights Reserved. 32 | 33 | JSON_checker 34 | Copyright (c) 2002 JSON.org 35 | All Rights Reserved. 36 | 37 | 38 | Terms of the JSON License: 39 | --------------------------------------------------- 40 | 41 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 42 | 43 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 44 | 45 | The Software shall be used for Good, not Evil. 46 | 47 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 48 | 49 | 50 | Terms of the MIT License: 51 | -------------------------------------------------------------------- 52 | 53 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 54 | 55 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 56 | 57 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 58 | -------------------------------------------------------------------------------- /3rd_party/include/zipkin/rapidjson/memorybuffer.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_MEMORYBUFFER_H_ 16 | #define RAPIDJSON_MEMORYBUFFER_H_ 17 | 18 | #include "stream.h" 19 | #include "internal/stack.h" 20 | 21 | RAPIDJSON_NAMESPACE_BEGIN 22 | 23 | //! Represents an in-memory output byte stream. 24 | /*! 25 | This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream. 26 | 27 | It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file. 28 | 29 | Differences between MemoryBuffer and StringBuffer: 30 | 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. 31 | 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator. 32 | 33 | \tparam Allocator type for allocating memory buffer. 34 | \note implements Stream concept 35 | */ 36 | template 37 | struct GenericMemoryBuffer { 38 | typedef char Ch; // byte 39 | 40 | GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} 41 | 42 | void Put(Ch c) { *stack_.template Push() = c; } 43 | void Flush() {} 44 | 45 | void Clear() { stack_.Clear(); } 46 | void ShrinkToFit() { stack_.ShrinkToFit(); } 47 | Ch* Push(size_t count) { return stack_.template Push(count); } 48 | void Pop(size_t count) { stack_.template Pop(count); } 49 | 50 | const Ch* GetBuffer() const { 51 | return stack_.template Bottom(); 52 | } 53 | 54 | size_t GetSize() const { return stack_.GetSize(); } 55 | 56 | static const size_t kDefaultCapacity = 256; 57 | mutable internal::Stack stack_; 58 | }; 59 | 60 | typedef GenericMemoryBuffer<> MemoryBuffer; 61 | 62 | //! Implement specialized version of PutN() with memset() for better performance. 63 | template<> 64 | inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) { 65 | std::memset(memoryBuffer.stack_.Push(n), c, n * sizeof(c)); 66 | } 67 | 68 | RAPIDJSON_NAMESPACE_END 69 | 70 | #endif // RAPIDJSON_MEMORYBUFFER_H_ 71 | -------------------------------------------------------------------------------- /3rd_party/include/zipkin/rapidjson/memorystream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_MEMORYSTREAM_H_ 16 | #define RAPIDJSON_MEMORYSTREAM_H_ 17 | 18 | #include "stream.h" 19 | 20 | #ifdef __clang__ 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(unreachable-code) 23 | RAPIDJSON_DIAG_OFF(missing-noreturn) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Represents an in-memory input byte stream. 29 | /*! 30 | This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream. 31 | 32 | It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file. 33 | 34 | Differences between MemoryStream and StringStream: 35 | 1. StringStream has encoding but MemoryStream is a byte stream. 36 | 2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source. 37 | 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4(). 38 | \note implements Stream concept 39 | */ 40 | struct MemoryStream { 41 | typedef char Ch; // byte 42 | 43 | MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} 44 | 45 | Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; } 46 | Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; } 47 | size_t Tell() const { return static_cast(src_ - begin_); } 48 | 49 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 50 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 51 | void Flush() { RAPIDJSON_ASSERT(false); } 52 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 53 | 54 | // For encoding detection only. 55 | const Ch* Peek4() const { 56 | return Tell() + 4 <= size_ ? src_ : 0; 57 | } 58 | 59 | const Ch* src_; //!< Current read position. 60 | const Ch* begin_; //!< Original head of the string. 61 | const Ch* end_; //!< End of stream. 62 | size_t size_; //!< Size of the stream. 63 | }; 64 | 65 | RAPIDJSON_NAMESPACE_END 66 | 67 | #ifdef __clang__ 68 | RAPIDJSON_DIAG_POP 69 | #endif 70 | 71 | #endif // RAPIDJSON_MEMORYBUFFER_H_ 72 | -------------------------------------------------------------------------------- /3rd_party/include/zipkin/rapidjson/ostreamwrapper.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_OSTREAMWRAPPER_H_ 16 | #define RAPIDJSON_OSTREAMWRAPPER_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | 21 | #ifdef __clang__ 22 | RAPIDJSON_DIAG_PUSH 23 | RAPIDJSON_DIAG_OFF(padded) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept. 29 | /*! 30 | The classes can be wrapped including but not limited to: 31 | 32 | - \c std::ostringstream 33 | - \c std::stringstream 34 | - \c std::wpstringstream 35 | - \c std::wstringstream 36 | - \c std::ifstream 37 | - \c std::fstream 38 | - \c std::wofstream 39 | - \c std::wfstream 40 | 41 | \tparam StreamType Class derived from \c std::basic_ostream. 42 | */ 43 | 44 | template 45 | class BasicOStreamWrapper { 46 | public: 47 | typedef typename StreamType::char_type Ch; 48 | BasicOStreamWrapper(StreamType& stream) : stream_(stream) {} 49 | 50 | void Put(Ch c) { 51 | stream_.put(c); 52 | } 53 | 54 | void Flush() { 55 | stream_.flush(); 56 | } 57 | 58 | // Not implemented 59 | char Peek() const { RAPIDJSON_ASSERT(false); return 0; } 60 | char Take() { RAPIDJSON_ASSERT(false); return 0; } 61 | size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } 62 | char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 63 | size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } 64 | 65 | private: 66 | BasicOStreamWrapper(const BasicOStreamWrapper&); 67 | BasicOStreamWrapper& operator=(const BasicOStreamWrapper&); 68 | 69 | StreamType& stream_; 70 | }; 71 | 72 | typedef BasicOStreamWrapper OStreamWrapper; 73 | typedef BasicOStreamWrapper WOStreamWrapper; 74 | 75 | #ifdef __clang__ 76 | RAPIDJSON_DIAG_POP 77 | #endif 78 | 79 | RAPIDJSON_NAMESPACE_END 80 | 81 | #endif // RAPIDJSON_OSTREAMWRAPPER_H_ 82 | -------------------------------------------------------------------------------- /3rd_party/include/zipkin/rapidjson/stream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #include "rapidjson.h" 16 | 17 | #ifndef RAPIDJSON_STREAM_H_ 18 | #define RAPIDJSON_STREAM_H_ 19 | 20 | #include "encodings.h" 21 | 22 | RAPIDJSON_NAMESPACE_BEGIN 23 | 24 | /////////////////////////////////////////////////////////////////////////////// 25 | // Stream 26 | 27 | /*! \class rapidjson::Stream 28 | \brief Concept for reading and writing characters. 29 | 30 | For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd(). 31 | 32 | For write-only stream, only need to implement Put() and Flush(). 33 | 34 | \code 35 | concept Stream { 36 | typename Ch; //!< Character type of the stream. 37 | 38 | //! Read the current character from stream without moving the read cursor. 39 | Ch Peek() const; 40 | 41 | //! Read the current character from stream and moving the read cursor to next character. 42 | Ch Take(); 43 | 44 | //! Get the current read cursor. 45 | //! \return Number of characters read from start. 46 | size_t Tell(); 47 | 48 | //! Begin writing operation at the current read pointer. 49 | //! \return The begin writer pointer. 50 | Ch* PutBegin(); 51 | 52 | //! Write a character. 53 | void Put(Ch c); 54 | 55 | //! Flush the buffer. 56 | void Flush(); 57 | 58 | //! End the writing operation. 59 | //! \param begin The begin write pointer returned by PutBegin(). 60 | //! \return Number of characters written. 61 | size_t PutEnd(Ch* begin); 62 | } 63 | \endcode 64 | */ 65 | 66 | //! Provides additional information for stream. 67 | /*! 68 | By using traits pattern, this type provides a default configuration for stream. 69 | For custom stream, this type can be specialized for other configuration. 70 | See TEST(Reader, CustomStringStream) in readertest.cpp for example. 71 | */ 72 | template 73 | struct StreamTraits { 74 | //! Whether to make local copy of stream for optimization during parsing. 75 | /*! 76 | By default, for safety, streams do not use local copy optimization. 77 | Stream that can be copied fast should specialize this, like StreamTraits. 78 | */ 79 | enum { copyOptimization = 0 }; 80 | }; 81 | 82 | //! Reserve n characters for writing to a stream. 83 | template 84 | inline void PutReserve(Stream& stream, size_t count) { 85 | (void)stream; 86 | (void)count; 87 | } 88 | 89 | //! Write character to a stream, presuming buffer is reserved. 90 | template 91 | inline void PutUnsafe(Stream& stream, typename Stream::Ch c) { 92 | stream.Put(c); 93 | } 94 | 95 | //! Put N copies of a character to a stream. 96 | template 97 | inline void PutN(Stream& stream, Ch c, size_t n) { 98 | PutReserve(stream, n); 99 | for (size_t i = 0; i < n; i++) 100 | PutUnsafe(stream, c); 101 | } 102 | 103 | /////////////////////////////////////////////////////////////////////////////// 104 | // StringStream 105 | 106 | //! Read-only string stream. 107 | /*! \note implements Stream concept 108 | */ 109 | template 110 | struct GenericStringStream { 111 | typedef typename Encoding::Ch Ch; 112 | 113 | GenericStringStream(const Ch *src) : src_(src), head_(src) {} 114 | 115 | Ch Peek() const { return *src_; } 116 | Ch Take() { return *src_++; } 117 | size_t Tell() const { return static_cast(src_ - head_); } 118 | 119 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 120 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 121 | void Flush() { RAPIDJSON_ASSERT(false); } 122 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 123 | 124 | const Ch* src_; //!< Current read position. 125 | const Ch* head_; //!< Original head of the string. 126 | }; 127 | 128 | template 129 | struct StreamTraits > { 130 | enum { copyOptimization = 1 }; 131 | }; 132 | 133 | //! String stream with UTF8 encoding. 134 | typedef GenericStringStream > StringStream; 135 | 136 | /////////////////////////////////////////////////////////////////////////////// 137 | // InsituStringStream 138 | 139 | //! A read-write string stream. 140 | /*! This string stream is particularly designed for in-situ parsing. 141 | \note implements Stream concept 142 | */ 143 | template 144 | struct GenericInsituStringStream { 145 | typedef typename Encoding::Ch Ch; 146 | 147 | GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {} 148 | 149 | // Read 150 | Ch Peek() { return *src_; } 151 | Ch Take() { return *src_++; } 152 | size_t Tell() { return static_cast(src_ - head_); } 153 | 154 | // Write 155 | void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } 156 | 157 | Ch* PutBegin() { return dst_ = src_; } 158 | size_t PutEnd(Ch* begin) { return static_cast(dst_ - begin); } 159 | void Flush() {} 160 | 161 | Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } 162 | void Pop(size_t count) { dst_ -= count; } 163 | 164 | Ch* src_; 165 | Ch* dst_; 166 | Ch* head_; 167 | }; 168 | 169 | template 170 | struct StreamTraits > { 171 | enum { copyOptimization = 1 }; 172 | }; 173 | 174 | //! Insitu string stream with UTF8 encoding. 175 | typedef GenericInsituStringStream > InsituStringStream; 176 | 177 | RAPIDJSON_NAMESPACE_END 178 | 179 | #endif // RAPIDJSON_STREAM_H_ 180 | -------------------------------------------------------------------------------- /3rd_party/include/zipkin/rapidjson/stringbuffer.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_STRINGBUFFER_H_ 16 | #define RAPIDJSON_STRINGBUFFER_H_ 17 | 18 | #include "stream.h" 19 | #include "internal/stack.h" 20 | 21 | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 22 | #include // std::move 23 | #endif 24 | 25 | #include "internal/stack.h" 26 | 27 | #if defined(__clang__) 28 | RAPIDJSON_DIAG_PUSH 29 | RAPIDJSON_DIAG_OFF(c++98-compat) 30 | #endif 31 | 32 | RAPIDJSON_NAMESPACE_BEGIN 33 | 34 | //! Represents an in-memory output stream. 35 | /*! 36 | \tparam Encoding Encoding of the stream. 37 | \tparam Allocator type for allocating memory buffer. 38 | \note implements Stream concept 39 | */ 40 | template 41 | class GenericStringBuffer { 42 | public: 43 | typedef typename Encoding::Ch Ch; 44 | 45 | GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} 46 | 47 | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 48 | GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {} 49 | GenericStringBuffer& operator=(GenericStringBuffer&& rhs) { 50 | if (&rhs != this) 51 | stack_ = std::move(rhs.stack_); 52 | return *this; 53 | } 54 | #endif 55 | 56 | void Put(Ch c) { *stack_.template Push() = c; } 57 | void PutUnsafe(Ch c) { *stack_.template PushUnsafe() = c; } 58 | void Flush() {} 59 | 60 | void Clear() { stack_.Clear(); } 61 | void ShrinkToFit() { 62 | // Push and pop a null terminator. This is safe. 63 | *stack_.template Push() = '\0'; 64 | stack_.ShrinkToFit(); 65 | stack_.template Pop(1); 66 | } 67 | 68 | void Reserve(size_t count) { stack_.template Reserve(count); } 69 | Ch* Push(size_t count) { return stack_.template Push(count); } 70 | Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe(count); } 71 | void Pop(size_t count) { stack_.template Pop(count); } 72 | 73 | const Ch* GetString() const { 74 | // Push and pop a null terminator. This is safe. 75 | *stack_.template Push() = '\0'; 76 | stack_.template Pop(1); 77 | 78 | return stack_.template Bottom(); 79 | } 80 | 81 | //! Get the size of string in bytes in the string buffer. 82 | size_t GetSize() const { return stack_.GetSize(); } 83 | 84 | //! Get the length of string in Ch in the string buffer. 85 | size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); } 86 | 87 | static const size_t kDefaultCapacity = 256; 88 | mutable internal::Stack stack_; 89 | 90 | private: 91 | // Prohibit copy constructor & assignment operator. 92 | GenericStringBuffer(const GenericStringBuffer&); 93 | GenericStringBuffer& operator=(const GenericStringBuffer&); 94 | }; 95 | 96 | //! String buffer with UTF8 encoding 97 | typedef GenericStringBuffer > StringBuffer; 98 | 99 | template 100 | inline void PutReserve(GenericStringBuffer& stream, size_t count) { 101 | stream.Reserve(count); 102 | } 103 | 104 | template 105 | inline void PutUnsafe(GenericStringBuffer& stream, typename Encoding::Ch c) { 106 | stream.PutUnsafe(c); 107 | } 108 | 109 | //! Implement specialized version of PutN() with memset() for better performance. 110 | template<> 111 | inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { 112 | std::memset(stream.stack_.Push(n), c, n * sizeof(c)); 113 | } 114 | 115 | RAPIDJSON_NAMESPACE_END 116 | 117 | #if defined(__clang__) 118 | RAPIDJSON_DIAG_POP 119 | #endif 120 | 121 | #endif // RAPIDJSON_STRINGBUFFER_H_ 122 | -------------------------------------------------------------------------------- /BUILD: -------------------------------------------------------------------------------- 1 | cc_library( 2 | name = "rapidjson", 3 | hdrs = glob(["3rd_party/include/zipkin/rapidjson/**/*.h"]), 4 | strip_include_prefix = "3rd_party/include", 5 | ) 6 | 7 | cc_library( 8 | name = "randutils", 9 | hdrs = glob(["3rd_party/include/zipkin/randutils/**/*.h"]), 10 | strip_include_prefix = "3rd_party/include", 11 | ) 12 | 13 | cc_library( 14 | name = "zipkin", 15 | srcs = glob(["zipkin/src/*.cc", "zipkin/src/*.h"]), 16 | hdrs = glob(["zipkin/include/zipkin/*.h"]), 17 | strip_include_prefix = "zipkin/include", 18 | visibility = ["//visibility:public"], 19 | deps = [ 20 | ":rapidjson", 21 | ":randutils", 22 | "@se_haxx_curl_libcurl//:curl", 23 | ] 24 | ) 25 | 26 | cc_library( 27 | name = "zipkin_opentracing", 28 | srcs = glob(["zipkin_opentracing/src/*.cc", "zipkin_opentracing/src/*.h"]), 29 | hdrs = glob(["zipkin_opentracing/include/zipkin/*.h"]), 30 | strip_include_prefix = "zipkin_opentracing/include", 31 | visibility = ["//visibility:public"], 32 | deps = [ 33 | ":zipkin", 34 | ":randutils", 35 | "@io_opentracing_cpp//:opentracing" 36 | ] 37 | ) 38 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(CPACK_RPM_COMPONENT_INSTALL ON) 2 | cmake_minimum_required(VERSION 3.0) 3 | 4 | project(zipkin-opentracing) 5 | 6 | set(ZIPKIN_VERSION_MAJOR "0") 7 | set(ZIPKIN_VERSION_MINOR "5") 8 | set(ZIPKIN_VERSION_PATCH "2") 9 | set(ZIPKIN_VERSION_STRING 10 | "${ZIPKIN_VERSION_MAJOR}.${ZIPKIN_VERSION_MINOR}.${ZIPKIN_VERSION_PATCH}") 11 | 12 | # ============================================================================== 13 | # Set up cpack 14 | 15 | SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "C++ implementation of Zipkin") 16 | SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md") 17 | SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") 18 | SET(CPACK_RPM_PACKAGE_GROUP "Development/Libraries") 19 | 20 | SET(CPACK_PACKAGE_VERSION_MAJOR ${ZIPKIN_VERSION_MAJOR}) 21 | SET(CPACK_PACKAGE_VERSION_MINOR ${ZIPKIN_VERSION_MINOR}) 22 | SET(CPACK_PACKAGE_VERSION_PATCH ${ZIPKIN_VERSION_PATCH}) 23 | set(CPACK_RPM_DIST_POST_INSTALL_SCRIPT_FILE ${CMAKE_SOURCE_DIR}/scripts/runldconfig) 24 | set(CPACK_RPM_DIST_POST_UNINSTALL_SCRIPT_FILE ${CMAKE_SOURCE_DIR}/scripts/runldconfig) 25 | set(CPACK_COMPONENTS_ALL DIST DEVEL) 26 | set(CPACK_COMPONENTS_GROUPING ONE_PER_GROUP) 27 | set(CPACK_GENERATOR "RPM") 28 | set(CPACK_COMPONENTS_IGNORE_GROUPS 1) 29 | 30 | set(CPACK_COMPONENT_DIST_REQUIRED TRUE) 31 | set(CPACK_COMPONENT_DEVEL_REQUIRED TRUE) 32 | 33 | include(CPack) 34 | # ============================================================================== 35 | 36 | option(BUILD_SHARED_LIBS "Build as a shared library" ON) 37 | option(BUILD_STATIC_LIBS "Build as a static library" ON) 38 | option(BUILD_PLUGIN "Build a plugin library" OFF) 39 | 40 | if (NOT BUILD_SHARED_LIBS AND NOT BUILD_STATIC_LIBS AND NOT BUILD_PLUGIN) 41 | message(FATAL_ERROR "One or all of BUILD_SHARED_LIBS, BUILD_STATIC_LIBS, or BUILD_PLUGIN must be set to ON to build") 42 | endif() 43 | 44 | set(CMAKE_CXX_STANDARD 11) 45 | include(CTest) 46 | 47 | set(CMAKE_THREAD_PREFER_PTHREAD TRUE) 48 | set(THREADS_PREFER_PTHREAD_FLAG TRUE) 49 | find_package(Threads REQUIRED) 50 | 51 | find_package(CURL) 52 | include_directories(SYSTEM ${CURL_INCLUDE_DIRS}) 53 | 54 | 55 | include_directories(SYSTEM 3rd_party/include) 56 | 57 | add_executable(embedfile 3rd_party/embedfile/src/embedfile.c) 58 | 59 | include_directories(zipkin/include) 60 | add_subdirectory(zipkin) 61 | 62 | include_directories(zipkin_opentracing/include) 63 | add_subdirectory(zipkin_opentracing) 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zipkin-cpp-opentracing 2 | OpenTracing implementation for Zipkin in C++. 3 | 4 | ## Dependencies 5 | 6 | * The [C++ OpenTracing Library](https://github.com/opentracing/opentracing-cpp). 7 | * [curl](https://curl.haxx.se/) 8 | 9 | ## Compile and install 10 | ``` 11 | mkdir .build 12 | cd .build 13 | cmake .. 14 | make 15 | sudo make install 16 | ``` 17 | 18 | ## Examples 19 | 20 | See [tutorial.cc](zipkin_opentracing/example/tutorial.cc). 21 | 22 | ## Dynamic loading 23 | 24 | The Zipkin tracer supports dynamic loading and construction from a JSON configuration. See the [schema](zipkin_opentracing/tracer_configuration.schema.json) for details on the JSON format. 25 | -------------------------------------------------------------------------------- /WORKSPACE: -------------------------------------------------------------------------------- 1 | workspace(name = "com_github_rnburn_zipkin_opentracing") 2 | 3 | load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") 4 | 5 | git_repository( 6 | name = "io_opentracing_cpp", 7 | remote = "https://github.com/opentracing/opentracing-cpp", 8 | commit = "ac50154a7713877f877981c33c3375003b6ebfe1", 9 | ) 10 | 11 | # TODO: Fill in libcurl dependency 12 | -------------------------------------------------------------------------------- /ci/BUILD.curl: -------------------------------------------------------------------------------- 1 | cc_library( 2 | name = "curl", 3 | srcs = ["lib/x86_64-linux-gnu/libcurl.so"], 4 | hdrs = glob(["include/x86_64-linux-gnu/curl/*.h"]), 5 | strip_include_prefix = "include/x86_64-linux-gnu/curl", 6 | visibility = ["//visibility:public"], 7 | ) 8 | -------------------------------------------------------------------------------- /ci/WORKSPACE: -------------------------------------------------------------------------------- 1 | workspace(name = "com_github_rnburn_zipkin_opentracing") 2 | 3 | load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") 4 | 5 | git_repository( 6 | name = "io_opentracing_cpp", 7 | remote = "https://github.com/opentracing/opentracing-cpp", 8 | commit = "4bb431f7728eaf383a07e86f9754a5b67575dab0", 9 | ) 10 | 11 | new_local_repository( 12 | name = "se_haxx_curl_libcurl", 13 | path = "/usr", 14 | build_file = "BUILD.curl" 15 | ) 16 | -------------------------------------------------------------------------------- /ci/build_plugin.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 | wget \ 9 | git \ 10 | ca-certificates 11 | 12 | export OPENTRACING_VERSION=1.6.0 13 | 14 | # Compile for a portable cpu architecture 15 | export CFLAGS="-march=x86-64" 16 | export CXXFLAGS="-march=x86-64" 17 | 18 | # Install libcurl 19 | CURL_VERSION=7.59.0 20 | cd "${BUILD_DIR}" 21 | wget https://curl.haxx.se/download/curl-${CURL_VERSION}.tar.gz 22 | tar zxf curl-${CURL_VERSION}.tar.gz 23 | cd curl-${CURL_VERSION} 24 | ./configure --prefix="${BUILD_DIR}" \ 25 | --disable-ftp \ 26 | --disable-ldap \ 27 | --disable-dict \ 28 | --disable-telnet \ 29 | --disable-tftp \ 30 | --disable-pop3 \ 31 | --disable-smtp \ 32 | --disable-gopher \ 33 | --without-ssl \ 34 | --disable-crypto-auth \ 35 | --without-axtls \ 36 | --disable-rtsp \ 37 | --enable-shared=no \ 38 | --enable-static=yes \ 39 | --with-pic 40 | make && make install 41 | 42 | # Build OpenTracing 43 | cd "${BUILD_DIR}" 44 | git clone -b v$OPENTRACING_VERSION https://github.com/opentracing/opentracing-cpp.git 45 | cd opentracing-cpp 46 | mkdir .build && cd .build 47 | cmake -DCMAKE_BUILD_TYPE=Release \ 48 | -DCMAKE_CXX_FLAGS="-fPIC" \ 49 | -DCMAKE_INSTALL_PREFIX="${BUILD_DIR}" \ 50 | -DBUILD_SHARED_LIBS=OFF \ 51 | -DBUILD_TESTING=OFF \ 52 | -DBUILD_MOCKTRACER=OFF \ 53 | .. 54 | make && make install 55 | 56 | # Build zipkin 57 | cd "${BUILD_DIR}" 58 | mkdir zipkin-cpp-opentracing && cd zipkin-cpp-opentracing 59 | cmake -DCMAKE_BUILD_TYPE=Release \ 60 | -DCMAKE_INSTALL_PREFIX="${BUILD_DIR}" \ 61 | -DBUILD_SHARED_LIBS=OFF \ 62 | -DBUILD_STATIC=OFF \ 63 | -DBUILD_TESTING=OFF \ 64 | -DBUILD_PLUGIN=ON \ 65 | "${SRC_DIR}" 66 | make && make install 67 | cp "${BUILD_DIR}"/lib/libzipkin_opentracing_plugin.so / 68 | -------------------------------------------------------------------------------- /ci/do_ci.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | [ -z "${SRC_DIR}" ] && export SRC_DIR="`pwd`" 6 | [ -z "${BUILD_DIR}" ] && export BUILD_DIR="`mktemp -d`" 7 | 8 | if [[ "$1" == "cmake.test" ]]; then 9 | cd "${BUILD_DIR}" 10 | cmake -DCMAKE_BUILD_TYPE=Debug "${SRC_DIR}" 11 | make 12 | make test 13 | exit 0 14 | elif [[ "$1" == "cmake.asan" ]]; then 15 | cd "${BUILD_DIR}" 16 | cmake -DCMAKE_BUILD_TYPE=Debug \ 17 | -DCMAKE_CXX_FLAGS="-fno-omit-frame-pointer -fsanitize=address" \ 18 | -DCMAKE_SHARED_LINKER_FLAGS="-fno-omit-frame-pointer -fsanitize=address" \ 19 | -DCMAKE_EXE_LINKER_FLAGS="-fno-omit-frame-pointer -fsanitize=address" \ 20 | "${SRC_DIR}" 21 | make VERBOSE=1 22 | make test 23 | exit 0 24 | elif [[ "$1" == "cmake.tsan" ]]; then 25 | cd "${BUILD_DIR}" 26 | cmake -DCMAKE_BUILD_TYPE=Debug \ 27 | -DCMAKE_CXX_FLAGS="-fno-omit-frame-pointer -fsanitize=thread" \ 28 | -DCMAKE_SHARED_LINKER_FLAGS="-fno-omit-frame-pointer -fsanitize=thread" \ 29 | -DCMAKE_EXE_LINKER_FLAGS="-fno-omit-frame-pointer -fsanitize=thread" \ 30 | "${SRC_DIR}" 31 | make VERBOSE=1 32 | make test 33 | exit 0 34 | elif [[ "$1" == "bazel.build" ]]; then 35 | cd ci 36 | bazel build -s --package_path=%workspace%:"${SRC_DIR}" //... 37 | exit 0 38 | elif [[ "$1" == "cmake.plugin" ]]; then 39 | "${SRC_DIR}"/ci//build_plugin.sh 40 | exit 0 41 | elif [[ "$1" == "release" ]]; then 42 | "${SRC_DIR}"/ci//build_plugin.sh 43 | "${SRC_DIR}"/ci/release.sh 44 | exit 0 45 | else 46 | echo "Invalid do_ci.sh target" 47 | exit 1 48 | fi 49 | -------------------------------------------------------------------------------- /ci/install_bazel.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | apt-get install --no-install-recommends --no-install-suggests -y \ 6 | curl \ 7 | ca-certificates \ 8 | openjdk-8-jdk \ 9 | gnupg2 \ 10 | g++ unzip zip 11 | 12 | echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" \ 13 | | tee /etc/apt/sources.list.d/bazel.list 14 | curl https://bazel.build/bazel-release.pub.gpg | apt-key add - 15 | apt-get update 16 | apt-get install --no-install-recommends --no-install-suggests -y bazel 17 | -------------------------------------------------------------------------------- /ci/install_dependencies.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | apt-get update 5 | apt-get install --no-install-recommends --no-install-suggests -y \ 6 | libcurl4-openssl-dev \ 7 | build-essential \ 8 | cmake \ 9 | git \ 10 | ca-certificates 11 | 12 | # Build OpenTracing 13 | cd / 14 | export OPENTRACING_VERSION=1.6.0 15 | git clone -b v$OPENTRACING_VERSION https://github.com/opentracing/opentracing-cpp.git 16 | cd opentracing-cpp 17 | mkdir .build && cd .build 18 | cmake -DBUILD_TESTING=OFF .. 19 | make && make install 20 | -------------------------------------------------------------------------------- /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 | 9 | # Install ghr 10 | cd / 11 | wget https://github.com/tcnksm/ghr/releases/download/v0.5.4/ghr_v0.5.4_linux_amd64.zip 12 | unzip ghr_v0.5.4_linux_amd64.zip 13 | 14 | # Create packaged plugins 15 | gzip -c /libzipkin_opentracing_plugin.so > /linux-amd64-libzipkin_opentracing_plugin.so.gz 16 | 17 | # Create release 18 | cd "${SRC_DIR}" 19 | VERSION_TAG="`git describe --abbrev=0 --tags`" 20 | 21 | RELEASE_TITLE="${VERSION_TAG/v/Release }" 22 | # No way to set title see https://github.com/tcnksm/ghr/issues/77 23 | 24 | echo "/ghr -t \ 25 | -u $CIRCLE_PROJECT_USERNAME \ 26 | -r $CIRCLE_PROJECT_REPONAME \ 27 | -replace \ 28 | "${VERSION_TAG}" \ 29 | /linux-amd64-libzipkin_opentracing_plugin.so.gz" 30 | /ghr -t $GITHUB_TOKEN \ 31 | -u $CIRCLE_PROJECT_USERNAME \ 32 | -r $CIRCLE_PROJECT_REPONAME \ 33 | -replace \ 34 | "${VERSION_TAG}" \ 35 | /linux-amd64-libzipkin_opentracing_plugin.so.gz 36 | -------------------------------------------------------------------------------- /scripts/run_clang_format.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | find . -path ./3rd_party -prune -o \( -name '*.h' -or -name '*.cc' \) \ 3 | -exec clang-format -i {} \; 4 | -------------------------------------------------------------------------------- /scripts/runldconfig: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | /sbin/ldconfig 3 | 4 | #This sets up the links between shared libraries after installation and uninstallation of RPMs. 5 | -------------------------------------------------------------------------------- /zipkin/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | install(DIRECTORY include/zipkin 2 | COMPONENT DEVEL 3 | DESTINATION include) 4 | set(ZIPKIN_SRCS src/zipkin_core_types.cc 5 | src/utility.cc 6 | src/hex.cc 7 | src/tracer.cc 8 | src/ip_address.cc 9 | src/span_buffer.cc 10 | src/span_context.cc 11 | src/zipkin_reporter_impl.cc 12 | src/zipkin_http_transporter.cc) 13 | 14 | set(WIN32_LIBRARIES) 15 | if(WIN32) 16 | list(APPEND WIN32_LIBRARIES wsock32.lib ws2_32.lib) 17 | endif() 18 | 19 | if (BUILD_SHARED_LIBS) 20 | add_library(zipkin SHARED ${ZIPKIN_SRCS}) 21 | target_link_libraries(zipkin Threads::Threads ${CURL_LIBRARIES} ${WIN32_LIBRARIES}) 22 | set_target_properties(zipkin PROPERTIES VERSION ${ZIPKIN_VERSION_STRING} 23 | SOVERSION ${ZIPKIN_VERSION_MAJOR}) 24 | install(TARGETS zipkin 25 | COMPONENT DIST 26 | LIBRARY DESTINATION lib) 27 | endif() 28 | 29 | if (BUILD_STATIC_LIBS) 30 | add_library(zipkin-static STATIC ${ZIPKIN_SRCS}) 31 | set_target_properties(zipkin-static PROPERTIES OUTPUT_NAME zipkin) 32 | target_link_libraries(zipkin-static Threads::Threads ${CURL_LIBRARIES} ${WIN32_LIBRARIES}) 33 | install(TARGETS zipkin-static 34 | ARCHIVE DESTINATION lib) 35 | endif() 36 | 37 | if (BUILD_PLUGIN) 38 | add_library(zipkin-plugin-static STATIC ${ZIPKIN_SRCS}) 39 | target_link_libraries(zipkin-plugin-static Threads::Threads ${CURL_LIBRARIES} ${WIN32_LIBRARIES}) 40 | set_property(TARGET zipkin-plugin-static PROPERTY POSITION_INDEPENDENT_CODE ON) 41 | endif() 42 | 43 | 44 | if(BUILD_TESTING AND BUILD_SHARED_LIBS) 45 | add_subdirectory(test) 46 | endif() 47 | -------------------------------------------------------------------------------- /zipkin/include/zipkin/flags.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace zipkin { 6 | 7 | // Flags provides the ability to create and communicate feature flags. 8 | using flags_t = uint64_t; 9 | 10 | const flags_t debug_flag = 1 << 0; 11 | 12 | // All flags below deal with binaryPropagators. They will be discarded in the 13 | // textMapPropagator (not read and not set) 14 | 15 | // SamplingSet and Sampled handle Sampled tribool logic for interop with 16 | // instrumenting libraries / propagation channels not using a separate Sampled 17 | // header and potentially encoding this in flags. 18 | // 19 | // When we receive a flag we do this: 20 | // 1. Sampled bit is set => true 21 | // 2. Sampled bit is not set => inspect SamplingSet bit. 22 | // 2a. SamplingSet bit is set => false 23 | // 2b. SamplingSet bit is not set => null 24 | // Note on 2b.: depending on the propagator having a separate Sampled header 25 | // we either assume Sampling is false or unknown. In the latter case we will 26 | // run our sampler even though we are not the root of the trace. 27 | // 28 | // When propagating to a downstream service we will always be explicit and 29 | // will provide a set SamplingSet bit in case of our binary propagator either 30 | const flags_t sampling_set_flag = 1 << 1; 31 | const flags_t sampled_flag = 1 << 2; 32 | 33 | // When set, we can ignore the value of the parentId. This is used for binary 34 | // fixed width transports or transports like proto3 that return a default 35 | // value if a value has not been set (thus not enabling you to distinguish 36 | // between the value being set to the default or not set at all). 37 | // 38 | // While many zipkin systems re-use a trace id as the root span id, we know 39 | // that some don't. With this flag, we can tell for sure if the span is root 40 | // as opposed to the convention trace id == span id == parent id. 41 | const flags_t is_root_flag = 1 << 3; 42 | } // namespace zipkin 43 | -------------------------------------------------------------------------------- /zipkin/include/zipkin/hex.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace zipkin { 9 | /** 10 | * Hex encoder/decoder. Produces lowercase hex digits. Can consume either 11 | * lowercase or uppercase digits. 12 | */ 13 | class Hex final { 14 | public: 15 | /** 16 | * Generates a hex dump of the given data 17 | * @param data the binary data to convert 18 | * @return the hex encoded string representing data 19 | */ 20 | static std::string encode(const std::vector &data) { 21 | return encode(&data[0], data.size()); 22 | } 23 | 24 | /** 25 | * Generates a hex dump of the given data 26 | * @param data the binary data to convert 27 | * @param length the length of the data 28 | * @return the hex encoded string representing data 29 | */ 30 | static std::string encode(const uint8_t *data, size_t length); 31 | 32 | /** 33 | * Converts a hex dump to binary data 34 | * @param input the hex dump to decode 35 | * @return binary data 36 | */ 37 | /* static std::vector decode(const std::string& input); */ 38 | 39 | /** 40 | * Converts the given 64-bit integer into a hexadecimal string. 41 | * @param value The integer to be converted. 42 | */ 43 | static std::string uint64ToHex(uint64_t value); 44 | 45 | /** 46 | * Converts the given TraceId into a hexadecimal string. 47 | * @param trace_id The TraceId to be converted. 48 | */ 49 | static std::string traceIdToHex(const TraceId &value); 50 | 51 | /** 52 | * Converts the given hexadecimal string into a 64-bit integer. 53 | * @param value The hexadecimal string to be converted. 54 | */ 55 | static Optional hexToUint64(const std::string &s); 56 | 57 | /** 58 | * Converts the given hexadecimal string into a TraceId. 59 | * @param value The hexadecimal string to be converted. 60 | */ 61 | static Optional hexToTraceId(const std::string &s); 62 | }; 63 | } // namespace zipkin 64 | -------------------------------------------------------------------------------- /zipkin/include/zipkin/ip_address.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace zipkin { 7 | enum class IpVersion { v4, v6 }; 8 | 9 | class IpAddress { 10 | public: 11 | IpAddress() = default; 12 | 13 | IpAddress(IpVersion version, const std::string &address); 14 | 15 | IpAddress(IpVersion version, const std::string &address, uint32_t port); 16 | 17 | IpVersion version() const { return version_; } 18 | 19 | uint32_t port() const { return port_; } 20 | 21 | const std::string &addressAsString() const { return friendly_address_; } 22 | 23 | bool valid() const { return !friendly_address_.empty(); } 24 | 25 | private: 26 | IpVersion version_; 27 | std::string friendly_address_; 28 | uint32_t port_; 29 | }; 30 | } // namespace zipkin 31 | -------------------------------------------------------------------------------- /zipkin/include/zipkin/optional.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace zipkin { 6 | /** 7 | * Contains an optional value. Like boost::optional and std::optional (not 8 | * included in C++11). 9 | */ 10 | template class Optional { 11 | public: 12 | Optional() {} 13 | Optional(const T &value) : value_(value), valid_(true) {} 14 | 15 | bool operator==(const Optional &rhs) const { 16 | if (valid_) { 17 | return valid_ == rhs.valid_ && value_ == rhs.value_; 18 | } else { 19 | return valid_ == rhs.valid_; 20 | } 21 | } 22 | 23 | /** 24 | * @return whether the contained value is valid. 25 | */ 26 | bool valid() const { return valid_; } 27 | 28 | /** 29 | * Set the contained value which will make it valid. 30 | */ 31 | void value(const T &new_value) { 32 | value_ = new_value; 33 | valid_ = true; 34 | } 35 | 36 | /** 37 | * @return the contained value. 38 | */ 39 | const T &value() const { 40 | assert(valid_); 41 | 42 | return value_; 43 | } 44 | 45 | /** 46 | * @return the contained value. 47 | */ 48 | T &value() { 49 | assert(valid_); 50 | 51 | return value_; 52 | } 53 | 54 | private: 55 | T value_; 56 | bool valid_{}; 57 | }; 58 | } // namespace zipkin 59 | -------------------------------------------------------------------------------- /zipkin/include/zipkin/span_context.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace zipkin { 12 | 13 | /** 14 | * This struct identifies which Zipkin annotations are present in the 15 | * span context (see SpanContext) 16 | * Each member is a one-bit boolean indicating whether or not the 17 | * corresponding annotation is present. 18 | * 19 | * In particular, the following annotations are tracked by this struct: 20 | * CS: "Client Send" 21 | * CR: "Client Receive" 22 | * SS: "Server Send" 23 | * SR: "Server Receive" 24 | */ 25 | struct AnnotationSet { 26 | AnnotationSet() : cs_(false), cr_(false), ss_(false), sr_(false) {} 27 | bool cs_ : 1; 28 | bool cr_ : 1; 29 | bool ss_ : 1; 30 | bool sr_ : 1; 31 | }; 32 | 33 | /** 34 | * This class represents the context of a Zipkin span. It embodies the following 35 | * span characteristics: trace id, span id, parent id, and basic annotations. 36 | */ 37 | class SpanContext { 38 | public: 39 | /** 40 | * Default constructor. Creates an empty context. 41 | */ 42 | SpanContext() 43 | : trace_id_(0), id_(0), parent_id_(), flags_(0), is_initialized_(false) {} 44 | 45 | /** 46 | * Constructor that creates a context object from the given Zipkin span 47 | * object. 48 | * 49 | * @param span The Zipkin span used to initialize a SpanContext object. 50 | */ 51 | SpanContext(const Span &span); 52 | 53 | /** 54 | * Constructor that creates a context object from the given IDs. 55 | */ 56 | SpanContext(const TraceId &trace_id, uint64_t id, 57 | const Optional &parent_id, flags_t flags) 58 | : trace_id_{trace_id}, id_{id}, parent_id_{parent_id}, flags_{flags}, 59 | is_initialized_{true} {} 60 | 61 | bool isSampled() const { return flags_ & zipkin::sampled_flag; } 62 | 63 | /** 64 | * @return the span id as an integer 65 | */ 66 | uint64_t id() const { return id_; } 67 | 68 | /** 69 | * @return the span id as a 16-character hexadecimal string. 70 | */ 71 | std::string idAsHexString() const { return Hex::uint64ToHex(id_); } 72 | 73 | /** 74 | * @return Whether or not the parent_id attribute is set. 75 | */ 76 | bool isSetParentId() const { return parent_id_.valid(); } 77 | 78 | /** 79 | * @return the span's parent id as an integer. 80 | */ 81 | TraceId parent_id() const { return parent_id_.value(); } 82 | 83 | /** 84 | * @return the parent id as a 16-character hexadecimal string. 85 | */ 86 | std::string parentIdAsHexString() const { 87 | return Hex::traceIdToHex(parent_id_.value()); 88 | } 89 | 90 | /** 91 | * @return the trace id as an integer. 92 | */ 93 | TraceId trace_id() const { return trace_id_; } 94 | 95 | /** 96 | * @return the trace id as a 16-character hexadecimal string. 97 | */ 98 | std::string traceIdAsHexString() const { 99 | return Hex::traceIdToHex(trace_id_); 100 | } 101 | 102 | /** 103 | * @return the flags as an integer. 104 | */ 105 | flags_t flags() const { return flags_; } 106 | 107 | /** 108 | * @return a struct indicating which annotations are present in the span. 109 | */ 110 | AnnotationSet annotationSet() const { return annotation_values_; } 111 | 112 | private: 113 | TraceId trace_id_; 114 | uint64_t id_; 115 | Optional parent_id_; 116 | AnnotationSet annotation_values_; 117 | flags_t flags_; 118 | bool is_initialized_; 119 | }; 120 | } // namespace zipkin 121 | -------------------------------------------------------------------------------- /zipkin/include/zipkin/trace_id.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace zipkin { 6 | class TraceId { 7 | public: 8 | TraceId() : high_{0}, low_{0} {} 9 | 10 | TraceId(uint64_t high, uint64_t low) : high_{high}, low_{low} {} 11 | 12 | TraceId(uint64_t low) : TraceId{0, low} {} 13 | 14 | uint64_t high() const { return high_; } 15 | 16 | uint64_t low() const { return low_; } 17 | 18 | bool empty() const { return high_ == 0 && low_ == 0; } 19 | 20 | private: 21 | uint64_t high_; 22 | uint64_t low_; 23 | }; 24 | 25 | inline bool operator==(const TraceId &lhs, const TraceId &rhs) { 26 | return lhs.high() == rhs.high() && lhs.low() == rhs.low(); 27 | } 28 | 29 | inline bool operator!=(const TraceId &lhs, const TraceId &rhs) { 30 | return !(lhs == rhs); 31 | } 32 | } // namespace zipkin 33 | -------------------------------------------------------------------------------- /zipkin/include/zipkin/tracer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace zipkin { 9 | const SteadyClock::duration DEFAULT_REPORTING_PERIOD = 10 | std::chrono::milliseconds{500}; 11 | const size_t DEFAULT_SPAN_BUFFER_SIZE = 1000; 12 | const std::chrono::milliseconds DEFAULT_TRANSPORT_TIMEOUT = std::chrono::milliseconds{0}; 13 | 14 | /** 15 | * Abstract class that delegates to users of the Tracer class the responsibility 16 | * of "reporting" a Zipkin span that has ended its life cycle. "Reporting" can 17 | * mean that the span will be sent to out to Zipkin, or buffered so that it can 18 | * be sent out later. 19 | */ 20 | class Reporter { 21 | public: 22 | /** 23 | * Destructor. 24 | */ 25 | virtual ~Reporter() {} 26 | 27 | /** 28 | * Method that a concrete Reporter class must implement to handle finished 29 | * spans. For example, a span-buffer management policy could be implemented. 30 | * 31 | * @param span The span that needs action. 32 | */ 33 | virtual void reportSpan(const Span &span) = 0; 34 | 35 | /** 36 | * Optional method that a concrete Reporter class can implement to flush 37 | * buffered spans. 38 | * 39 | * @param timeout The timeout to use when flushing. 40 | */ 41 | virtual bool flushWithTimeout(std::chrono::system_clock::duration timeout) { 42 | return true; 43 | } 44 | }; 45 | 46 | typedef std::unique_ptr ReporterPtr; 47 | 48 | /** 49 | * Construct a Reporter that sends spans to a Zipkin service via HTTP. 50 | * 51 | * @param collector_host The host to use when sending spans to the Zipkin 52 | * service. 53 | * @param collector_port The port to use when sending spans to the Zipkin 54 | * service. 55 | * @return a Reporter object. 56 | */ 57 | ReporterPtr makeHttpReporter( 58 | const char *collector_host, uint32_t collector_port, 59 | std::chrono::milliseconds collector_timeout = DEFAULT_TRANSPORT_TIMEOUT, 60 | SteadyClock::duration reporting_period = DEFAULT_REPORTING_PERIOD, 61 | size_t max_buffered_spans = DEFAULT_SPAN_BUFFER_SIZE); 62 | 63 | /** 64 | * This class implements the Zipkin tracer. It has methods to create the 65 | * appropriate Zipkin span type, i.e., root span, child span, or shared-context 66 | * span. 67 | * 68 | * This class allows its users to supply a concrete Reporter class whose 69 | * reportSpan method 70 | * is called by its own reportSpan method. By doing so, we have cleanly 71 | * separated the logic 72 | * of dealing with finished spans from the span-creation and tracing logic. 73 | */ 74 | class Tracer : public TracerInterface { 75 | public: 76 | /** 77 | * Constructor. 78 | * 79 | * @param service_name The name of the service where the Tracer is running. 80 | * This name is used in all annotations' endpoints of the spans created by the 81 | * Tracer. 82 | * @param address Pointer to a network-address object. The IP address and port 83 | * are used in all annotations' endpoints of the spans created by the Tracer. 84 | */ 85 | Tracer(const std::string &service_name, const IpAddress &address) 86 | : service_name_(service_name), address_(address), reporter_(nullptr) {} 87 | 88 | /** 89 | * Creates a "root" Zipkin span. 90 | * 91 | * @param span_name Name of the new span. 92 | * @param start_time The time indicating the beginning of the span. 93 | */ 94 | SpanPtr startSpan(const std::string &span_name, SystemTime timestamp); 95 | 96 | /** 97 | * Depending on the given context, creates either a "child" or a 98 | * "shared-context" Zipkin span. 99 | * 100 | * @param span_name Name of the new span. 101 | * @param start_time The time indicating the beginning of the span. 102 | * @param previous_context The context of the span preceding the one to be 103 | * created. 104 | */ 105 | SpanPtr startSpan(const std::string &span_name, SystemTime timestamp, 106 | const SpanContext &previous_context); 107 | 108 | /** 109 | * TracerInterface::reportSpan. 110 | */ 111 | void reportSpan(Span &&span) override; 112 | 113 | /** 114 | * @return the service-name attribute associated with the Tracer. 115 | */ 116 | const std::string &serviceName() const { return service_name_; } 117 | 118 | /** 119 | * @return the pointer to the address object associated with the Tracer. 120 | */ 121 | const IpAddress &address() const { return address_; } 122 | 123 | /** 124 | * Associates a Reporter object with this Tracer. 125 | */ 126 | void setReporter(ReporterPtr reporter); 127 | 128 | /** 129 | * Optional method that a concrete Reporter class can implement to flush 130 | * buffered spans. 131 | * 132 | * @param timeout The timeout to use when flushing. 133 | */ 134 | bool flushWithTimeout(std::chrono::system_clock::duration timeout) { 135 | if (reporter_) 136 | return reporter_->flushWithTimeout(timeout); 137 | return false; 138 | } 139 | 140 | private: 141 | const std::string service_name_; 142 | IpAddress address_; 143 | ReporterPtr reporter_; 144 | }; 145 | 146 | typedef std::unique_ptr TracerPtr; 147 | 148 | } // namespace zipkin 149 | -------------------------------------------------------------------------------- /zipkin/include/zipkin/tracer_interface.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace zipkin { 4 | 5 | class Span; 6 | 7 | /** 8 | * This interface must be observed by a Zipkin tracer. 9 | */ 10 | class TracerInterface { 11 | public: 12 | /** 13 | * Destructor. 14 | */ 15 | virtual ~TracerInterface() {} 16 | 17 | /** 18 | * A Zipkin tracer must implement this method. Its implementation must perform 19 | * whatever 20 | * actions are required when the given span is considered finished. An 21 | * implementation 22 | * will typically buffer the given span so that it can be flushed later. 23 | * 24 | * This method is invoked by the Span object when its finish() method is 25 | * called. 26 | * 27 | * @param span The span that needs action. 28 | */ 29 | virtual void reportSpan(Span &&span) = 0; 30 | }; 31 | } // namespace zipkin 32 | -------------------------------------------------------------------------------- /zipkin/include/zipkin/utility.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace zipkin { 11 | using SystemClock = std::chrono::system_clock; 12 | using SteadyClock = std::chrono::steady_clock; 13 | using SystemTime = SystemClock::time_point; 14 | using SteadyTime = SteadyClock::time_point; 15 | 16 | /** 17 | * Utility routines for working with random number generation. 18 | */ 19 | class RandomUtil { 20 | public: 21 | static uint64_t generateId(); 22 | }; 23 | 24 | /** 25 | * Utility routines for working with strings. 26 | */ 27 | class StringUtil { 28 | public: 29 | /** 30 | * Convert a string to an unsigned long, checking for error. 31 | * @param return TRUE if successful, FALSE otherwise. 32 | */ 33 | static bool atoul(const char *str, uint64_t &out, int base = 10); 34 | 35 | /** 36 | * Convert a string to an unsigned long long, checking for error. 37 | * @param return TRUE if successful, FALSE otherwise. 38 | */ 39 | static bool atoull(const char *str, uint64_t &out, int base = 10); 40 | 41 | /** 42 | * Perform a case insensitive compare of 2 strings. 43 | * @param lhs supplies string 1. 44 | * @param rhs supplies string 2. 45 | * @return < 0, 0, > 0 depending on the comparison result. 46 | */ 47 | static int caseInsensitiveCompare(const char *lhs, const char *rhs) { 48 | return strcasecmp(lhs, rhs); 49 | } 50 | 51 | /** 52 | * Convert an unsigned integer to a base 10 string as fast as possible. 53 | * @param out supplies the string to fill. 54 | * @param out_len supplies the length of the output buffer. Must be >= 21. 55 | * @param i supplies the number to convert. 56 | * @return the size of the string, not including the null termination. 57 | */ 58 | static uint32_t itoa(char *out, size_t out_len, uint64_t i); 59 | 60 | /** 61 | * Trim trailing whitespace from a string in place. 62 | */ 63 | static void rtrim(std::string &source); 64 | 65 | /** 66 | * Size-bounded string copying and concatenation 67 | */ 68 | static size_t strlcpy(char *dst, const char *src, size_t size); 69 | 70 | /** 71 | * Split a string. 72 | * @param source supplies the string to split. 73 | * @param split supplies the string to split on. 74 | * @param keep_empty_string result contains empty strings if the string starts 75 | * or ends with 76 | * 'split', or if instances of 'split' are adjacent. 77 | * @return vector of strings computed after splitting `source` around all 78 | * instances of `split`. 79 | */ 80 | static std::vector split(const std::string &source, 81 | const std::string &split, 82 | bool keep_empty_string = false); 83 | 84 | /** 85 | * Join elements of a vector into a string delimited by delimiter. 86 | * @param source supplies the strings to join. 87 | * @param delimiter supplies the delimiter to join them together. 88 | * @return string combining elements of `source` with `delimiter` in between 89 | * each element. 90 | */ 91 | static std::string join(const std::vector &source, 92 | const std::string &delimiter); 93 | 94 | /** 95 | * Split a string. 96 | * @param source supplies the string to split. 97 | * @param split supplies the char to split on. 98 | * @return vector of strings computed after splitting `source` around all 99 | * instances of `split`. 100 | */ 101 | static std::vector split(const std::string &source, char split); 102 | 103 | /** 104 | * Version of substr() that operates on a start and end index instead of a 105 | * start index and a 106 | * length. 107 | */ 108 | static std::string subspan(const std::string &source, size_t start, 109 | size_t end); 110 | 111 | /** 112 | * Escape strings for logging purposes. Returns a copy of the string with 113 | * \n, \r, \t, and " (double quote) escaped. 114 | * @param source supplies the string to escape. 115 | * @return escaped string. 116 | */ 117 | static std::string escape(const std::string &source); 118 | 119 | /** 120 | * @return true if @param source ends with @param end. 121 | */ 122 | static bool endsWith(const std::string &source, const std::string &end); 123 | 124 | /** 125 | * @param case_sensitive determines if the compare is case sensitive 126 | * @return true if @param source starts with @param start and ignores cases. 127 | */ 128 | static bool startsWith(const char *source, const std::string &start, 129 | bool case_sensitive = true); 130 | }; 131 | 132 | /** 133 | * Utility routines for working with json. 134 | */ 135 | class JsonUtil { 136 | public: 137 | // ==== 138 | // Stringified-JSON manipulation 139 | // ==== 140 | 141 | /** 142 | * Merges the stringified JSONs given in target and source. 143 | * 144 | * @param target It will contain the resulting stringified JSON. 145 | * @param source The stringified JSON that will be added to target. 146 | * @param field_name The key name (added to target's JSON) whose value will be 147 | * the JSON in source. 148 | */ 149 | static void mergeJsons(std::string &target, const std::string &source, 150 | const std::string &field_name); 151 | 152 | /** 153 | * Merges a stringified JSON and a vector of stringified JSONs. 154 | * 155 | * @param target It will contain the resulting stringified JSON. 156 | * @param json_array Vector of strings, where each element is a stringified 157 | * JSON. 158 | * @param field_name The key name (added to target's JSON) whose value will be 159 | * a stringified. 160 | * JSON array derived from json_array. 161 | */ 162 | static void addArrayToJson(std::string &target, 163 | const std::vector &json_array, 164 | const std::string &field_name); 165 | }; 166 | } // namespace zipkin 167 | -------------------------------------------------------------------------------- /zipkin/src/hex.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace zipkin { 11 | std::string Hex::encode(const uint8_t *data, size_t length) { 12 | static const char *const digits = "0123456789abcdef"; 13 | 14 | std::string ret; 15 | ret.reserve(length * 2); 16 | 17 | for (size_t i = 0; i < length; i++) { 18 | uint8_t d = data[i]; 19 | ret.push_back(digits[d >> 4]); 20 | ret.push_back(digits[d & 0xf]); 21 | } 22 | 23 | return ret; 24 | } 25 | 26 | static std::vector decode(const std::string &hex_string) { 27 | if (hex_string.empty()) { 28 | return {}; 29 | } 30 | auto num_bytes = hex_string.size() / 2 + (hex_string.size() % 2 > 0); 31 | std::vector result; 32 | result.reserve(num_bytes); 33 | 34 | std::vector segment; 35 | segment.reserve(num_bytes); 36 | size_t i = 0; 37 | std::string hex_byte; 38 | hex_byte.reserve(2); 39 | uint64_t out; 40 | 41 | if (hex_string.size() % 2 == 1) { 42 | hex_byte = hex_string.substr(0, 1); 43 | if (!StringUtil::atoul(hex_byte.c_str(), out, 16)) { 44 | return {}; 45 | } 46 | segment.push_back(out); 47 | i = 1; 48 | } 49 | 50 | for (; i < hex_string.size(); i += 2) { 51 | hex_byte = hex_string.substr(i, 2); 52 | if (!StringUtil::atoul(hex_byte.c_str(), out, 16)) { 53 | return {}; 54 | } 55 | 56 | segment.push_back(out); 57 | } 58 | 59 | return segment; 60 | } 61 | 62 | std::string Hex::uint64ToHex(uint64_t value) { 63 | std::array data; 64 | 65 | // This is explicitly done for performance reasons 66 | data[7] = (value & 0x00000000000000FF); 67 | data[6] = (value & 0x000000000000FF00) >> 8; 68 | data[5] = (value & 0x0000000000FF0000) >> 16; 69 | data[4] = (value & 0x00000000FF000000) >> 24; 70 | data[3] = (value & 0x000000FF00000000) >> 32; 71 | data[2] = (value & 0x0000FF0000000000) >> 40; 72 | data[1] = (value & 0x00FF000000000000) >> 48; 73 | data[0] = (value & 0xFF00000000000000) >> 56; 74 | 75 | return encode(&data[0], data.size()); 76 | } 77 | 78 | std::string Hex::traceIdToHex(const TraceId &trace_id) { 79 | std::string result; 80 | if (trace_id.high() == 0) { 81 | result.reserve(16); 82 | result = Hex::uint64ToHex(trace_id.low()); 83 | } else { 84 | result.reserve(32); 85 | result.append(Hex::uint64ToHex(trace_id.high())); 86 | result.append(Hex::uint64ToHex(trace_id.low())); 87 | } 88 | return result; 89 | } 90 | 91 | Optional Hex::hexToUint64(const std::string &s) { 92 | auto data = decode(s); 93 | if (data.empty() || data.size() > 8) { 94 | return {}; 95 | } 96 | uint64_t result = 0; 97 | for (auto d : data) { 98 | result = result * 256 + d; 99 | } 100 | return result; 101 | } 102 | 103 | Optional Hex::hexToTraceId(const std::string &s) { 104 | auto data = decode(s); 105 | if (data.empty() || data.size() > 16) { 106 | return {}; 107 | } 108 | uint64_t trace_id_high = 0; 109 | uint64_t trace_id_low = 0; 110 | size_t num_bytes_low = std::min(8, data.size()); 111 | size_t num_bytes_high = data.size() - num_bytes_low; 112 | for (size_t i = 0; i < num_bytes_high; ++i) { 113 | trace_id_high = trace_id_high * 256 + data[i]; 114 | } 115 | for (size_t i = num_bytes_high; i < data.size(); ++i) { 116 | trace_id_low = trace_id_low * 256 + data[i]; 117 | } 118 | return TraceId{trace_id_high, trace_id_low}; 119 | } 120 | } // namespace zipkin 121 | -------------------------------------------------------------------------------- /zipkin/src/ip_address.cc: -------------------------------------------------------------------------------- 1 | #ifdef _MSC_VER 2 | #include 3 | #else 4 | #include 5 | #endif 6 | #include 7 | #include 8 | #include 9 | 10 | namespace zipkin { 11 | static bool isValidIpv4Address(const std::string &address) { 12 | in_addr sin_addr = {}; 13 | int rc = inet_pton(AF_INET, address.c_str(), &sin_addr); 14 | return rc == 1; 15 | } 16 | 17 | static std::string makeFriendlyIpv6Address(const std::string &address) { 18 | in6_addr sin6_addr = {}; 19 | int rc = inet_pton(AF_INET6, address.c_str(), &sin6_addr); 20 | if (rc != 1) { 21 | return {}; 22 | } 23 | char str[INET6_ADDRSTRLEN]; 24 | const char *ptr = inet_ntop(AF_INET6, &sin6_addr, str, INET6_ADDRSTRLEN); 25 | return ptr; 26 | } 27 | 28 | IpAddress::IpAddress(IpVersion version, const std::string &address) 29 | : IpAddress{version, address, 0} {} 30 | 31 | IpAddress::IpAddress(IpVersion version, const std::string &address, 32 | uint32_t port) 33 | : version_{version}, friendly_address_{}, port_{0} { 34 | switch (version) { 35 | case IpVersion::v4: { 36 | if (!isValidIpv4Address(address)) { 37 | return; 38 | } 39 | friendly_address_ = address + ":" + std::to_string(port); 40 | } 41 | case IpVersion::v6: { 42 | auto normalized_address = makeFriendlyIpv6Address(address); 43 | if (normalized_address.empty()) { 44 | return; 45 | } 46 | friendly_address_ = 47 | std::string{"["} + normalized_address + "]:" + std::to_string(port); 48 | } 49 | } 50 | port_ = port; 51 | } 52 | } // namespace zipkin 53 | -------------------------------------------------------------------------------- /zipkin/src/singleton.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace zipkin { 4 | /** 5 | * Immutable singleton pattern. 6 | */ 7 | template class ConstSingleton { 8 | public: 9 | /** 10 | * Obtain an instance of the singleton for class T. 11 | * @return const T& a reference to the singleton for class T. 12 | */ 13 | static const T &get() { 14 | static T *instance = new T(); 15 | return *instance; 16 | } 17 | }; 18 | } // namespace zipkin 19 | -------------------------------------------------------------------------------- /zipkin/src/span_buffer.cc: -------------------------------------------------------------------------------- 1 | #include "span_buffer.h" 2 | 3 | namespace zipkin { 4 | 5 | // TODO(fabolive): Need to avoid the copy to improve performance. 6 | bool SpanBuffer::addSpan(const Span &span) { 7 | if (span_buffer_.size() == span_buffer_.capacity()) { 8 | // Buffer full 9 | return false; 10 | } 11 | span_buffer_.push_back(std::move(span)); 12 | 13 | return true; 14 | } 15 | 16 | std::string SpanBuffer::toStringifiedJsonArray() { 17 | std::string stringified_json_array = "["; 18 | 19 | if (pendingSpans()) { 20 | stringified_json_array += span_buffer_[0].toJson(); 21 | const uint64_t size = span_buffer_.size(); 22 | for (uint64_t i = 1; i < size; i++) { 23 | stringified_json_array += ","; 24 | stringified_json_array += span_buffer_[i].toJson(); 25 | } 26 | } 27 | stringified_json_array += "]"; 28 | 29 | return stringified_json_array; 30 | } 31 | } // namespace zipkin 32 | -------------------------------------------------------------------------------- /zipkin/src/span_buffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace zipkin { 6 | 7 | /** 8 | * This class implements a simple buffer to store Zipkin tracing spans 9 | * prior to flushing them. 10 | */ 11 | class SpanBuffer { 12 | public: 13 | /** 14 | * Constructor that creates an empty buffer. Space needs to be allocated by 15 | * invoking the method allocateBuffer(size). 16 | */ 17 | SpanBuffer() {} 18 | 19 | /** 20 | * Constructor that initializes a buffer with the given size. 21 | * 22 | * @param size The desired buffer size. 23 | */ 24 | SpanBuffer(uint64_t size) { allocateBuffer(size); } 25 | 26 | /** 27 | * Allocates space for an empty buffer or resizes a previously-allocated one. 28 | * 29 | * @param size The desired buffer size. 30 | */ 31 | void allocateBuffer(uint64_t size) { span_buffer_.reserve(size); } 32 | 33 | /** 34 | * Adds the given Zipkin span to the buffer. 35 | * 36 | * @param span The span to be added to the buffer. 37 | * 38 | * @return true if the span was successfully added, or false if the buffer was 39 | * full. 40 | */ 41 | bool addSpan(const Span &span); 42 | 43 | /** 44 | * @return returns the number of spans that can be held in currently allocated 45 | * storage. 46 | */ 47 | uint64_t spanCapacity() const { return span_buffer_.capacity(); } 48 | 49 | /** 50 | * Empties the buffer. This method is supposed to be called when all buffered 51 | * spans have been sent to to the Zipkin service. 52 | */ 53 | void clear() { span_buffer_.clear(); } 54 | 55 | /** 56 | * Swaps buffers. 57 | */ 58 | void swap(SpanBuffer &other) { span_buffer_.swap(other.span_buffer_); } 59 | 60 | /** 61 | * @return the number of spans currently buffered. 62 | */ 63 | uint64_t pendingSpans() { return span_buffer_.size(); } 64 | 65 | /** 66 | * @return the contents of the buffer as a stringified array of JSONs, where 67 | * each JSON in the array corresponds to one Zipkin span. 68 | */ 69 | std::string toStringifiedJsonArray(); 70 | 71 | private: 72 | // We use a pre-allocated vector to improve performance 73 | std::vector span_buffer_; 74 | }; 75 | } // namespace zipkin 76 | -------------------------------------------------------------------------------- /zipkin/src/span_context.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "zipkin_core_constants.h" 4 | #include 5 | 6 | namespace zipkin { 7 | SpanContext::SpanContext(const Span &span) { 8 | trace_id_ = span.traceId(); 9 | id_ = span.id(); 10 | parent_id_ = span.isSetParentId() ? span.parentId() : 0; 11 | flags_ = 0; 12 | 13 | if (span.isSampled()) { 14 | flags_ |= static_cast(zipkin::sampled_flag); 15 | } 16 | 17 | for (const Annotation &annotation : span.annotations()) { 18 | if (annotation.value() == ZipkinCoreConstants::get().CLIENT_RECV) { 19 | annotation_values_.cr_ = true; 20 | } else if (annotation.value() == ZipkinCoreConstants::get().CLIENT_SEND) { 21 | annotation_values_.cs_ = true; 22 | } else if (annotation.value() == ZipkinCoreConstants::get().SERVER_RECV) { 23 | annotation_values_.sr_ = true; 24 | } else if (annotation.value() == ZipkinCoreConstants::get().SERVER_SEND) { 25 | annotation_values_.ss_ = true; 26 | } 27 | } 28 | 29 | is_initialized_ = true; 30 | } 31 | } // namespace zipkin 32 | -------------------------------------------------------------------------------- /zipkin/src/tracer.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "zipkin_core_constants.h" 6 | #include 7 | 8 | namespace zipkin { 9 | SpanPtr Tracer::startSpan(const std::string &span_name, SystemTime timestamp) { 10 | // Build the endpoint 11 | Endpoint ep(service_name_, address_); 12 | 13 | // Create an all-new span, with no parent id 14 | SpanPtr span_ptr(new Span()); 15 | span_ptr->setName(span_name); 16 | uint64_t random_number = RandomUtil::generateId(); 17 | span_ptr->setId(random_number); 18 | span_ptr->setTraceId(random_number); 19 | int64_t start_time_micro = 20 | std::chrono::duration_cast( 21 | SteadyClock::now().time_since_epoch()) 22 | .count(); 23 | span_ptr->setStartTime(start_time_micro); 24 | 25 | // Set the timestamp globally for the span and also for the CS annotation 26 | uint64_t timestamp_micro = 27 | std::chrono::duration_cast( 28 | timestamp.time_since_epoch()) 29 | .count(); 30 | span_ptr->setTimestamp(timestamp_micro); 31 | 32 | span_ptr->setTracer(this); 33 | 34 | return span_ptr; 35 | } 36 | 37 | SpanPtr Tracer::startSpan(const std::string &span_name, SystemTime timestamp, 38 | const SpanContext &previous_context) { 39 | SpanPtr span_ptr(new Span()); 40 | Annotation annotation; 41 | uint64_t timestamp_micro; 42 | 43 | timestamp_micro = std::chrono::duration_cast( 44 | timestamp.time_since_epoch()) 45 | .count(); 46 | 47 | if (previous_context.annotationSet().sr_ && 48 | !previous_context.annotationSet().cs_) { 49 | // We need to create a new span that is a child of the previous span; no 50 | // shared context 51 | 52 | // Create a new span id 53 | uint64_t random_number = RandomUtil::generateId(); 54 | span_ptr->setId(random_number); 55 | 56 | span_ptr->setName(span_name); 57 | 58 | // Set the parent id to the id of the previous span 59 | span_ptr->setParentId(previous_context.id()); 60 | 61 | // Set the CS annotation value 62 | annotation.setValue(ZipkinCoreConstants::get().CLIENT_SEND); 63 | 64 | // Set the timestamp globally for the span 65 | span_ptr->setTimestamp(timestamp_micro); 66 | } else if (previous_context.annotationSet().cs_ && 67 | !previous_context.annotationSet().sr_) { 68 | // We need to create a new span that will share context with the previous 69 | // span 70 | 71 | // Initialize the shared context for the new span 72 | span_ptr->setId(previous_context.id()); 73 | if (!previous_context.parent_id().empty()) { 74 | span_ptr->setParentId(previous_context.parent_id()); 75 | } 76 | 77 | // Set the SR annotation value 78 | annotation.setValue(ZipkinCoreConstants::get().SERVER_RECV); 79 | } else { 80 | return span_ptr; // return an empty span 81 | } 82 | 83 | // Build the endpoint 84 | Endpoint ep(service_name_, address_); 85 | 86 | // Add the newly-created annotation to the span 87 | annotation.setEndpoint(std::move(ep)); 88 | annotation.setTimestamp(timestamp_micro); 89 | span_ptr->addAnnotation(std::move(annotation)); 90 | 91 | // Keep the same trace id 92 | span_ptr->setTraceId(previous_context.trace_id()); 93 | 94 | int64_t start_time_micro = 95 | std::chrono::duration_cast( 96 | SteadyClock::now().time_since_epoch()) 97 | .count(); 98 | span_ptr->setStartTime(start_time_micro); 99 | 100 | span_ptr->setTracer(this); 101 | 102 | return span_ptr; 103 | } 104 | 105 | void Tracer::reportSpan(Span &&span) { 106 | if (reporter_) { 107 | reporter_->reportSpan(std::move(span)); 108 | } 109 | } 110 | 111 | void Tracer::setReporter(ReporterPtr reporter) { 112 | reporter_ = std::move(reporter); 113 | } 114 | } // namespace zipkin 115 | -------------------------------------------------------------------------------- /zipkin/src/transporter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "span_buffer.h" 4 | 5 | namespace zipkin { 6 | /** 7 | * Abstract class that delegates to users of the Tracer class the responsibility 8 | * of "transporting" Zipkin spans that have ended its life cycle. 9 | */ 10 | class Transporter { 11 | public: 12 | /** 13 | * Destructor. 14 | */ 15 | virtual ~Transporter() {} 16 | 17 | /** 18 | * Method that a concrete Transporter class must implement to handle finished 19 | * spans. 20 | * 21 | * @param spans The SpanBuffer that needs action. 22 | */ 23 | virtual void transportSpans(SpanBuffer &spans) = 0; 24 | }; 25 | 26 | typedef std::unique_ptr TransporterPtr; 27 | } // namespace zipkin 28 | -------------------------------------------------------------------------------- /zipkin/src/utility.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace zipkin { 20 | // Wrapper for a seeded random number generator that works with forking. 21 | // 22 | // See https://stackoverflow.com/q/51882689/4447365 and 23 | // https://github.com/opentracing-contrib/nginx-opentracing/issues/52 24 | namespace { 25 | class TlsRandomNumberGenerator { 26 | public: 27 | TlsRandomNumberGenerator() { pthread_atfork(nullptr, nullptr, onFork); } 28 | 29 | static std::mt19937_64 &engine() { return base_generator_.engine(); } 30 | 31 | private: 32 | static thread_local randutils::mt19937_64_rng base_generator_; 33 | 34 | static void onFork() { base_generator_.seed(); } 35 | }; 36 | 37 | thread_local randutils::mt19937_64_rng 38 | TlsRandomNumberGenerator::base_generator_; 39 | } // namespace 40 | 41 | std::mt19937_64 &getTlsRandomEngine() { 42 | static TlsRandomNumberGenerator rng; 43 | return TlsRandomNumberGenerator::engine(); 44 | } 45 | 46 | uint64_t RandomUtil::generateId() { return getTlsRandomEngine()(); } 47 | 48 | bool StringUtil::atoul(const char *str, uint64_t &out, int base) { 49 | if (strlen(str) == 0) { 50 | return false; 51 | } 52 | 53 | char *end_ptr; 54 | out = strtoul(str, &end_ptr, base); 55 | if (*end_ptr != '\0' || (out == ULONG_MAX && errno == ERANGE)) { 56 | return false; 57 | } else { 58 | return true; 59 | } 60 | } 61 | 62 | bool StringUtil::atoull(const char *str, uint64_t &out, int base) { 63 | if (strlen(str) == 0) { 64 | return false; 65 | } 66 | 67 | char *end_ptr; 68 | out = strtoull(str, &end_ptr, base); 69 | if (*end_ptr != '\0' || 70 | (out == std::numeric_limits::max() && errno == ERANGE)) { 71 | return false; 72 | } else { 73 | return true; 74 | } 75 | } 76 | 77 | uint32_t StringUtil::itoa(char *out, size_t buffer_size, uint64_t i) { 78 | // The maximum size required for an unsigned 64-bit integer is 21 chars 79 | // (including null). 80 | if (buffer_size < 21) { 81 | throw std::invalid_argument("itoa buffer too small"); 82 | } 83 | 84 | char *current = out; 85 | do { 86 | *current++ = "0123456789"[i % 10]; 87 | i /= 10; 88 | } while (i > 0); 89 | 90 | for (uint64_t i = 0, j = current - out - 1; i < j; i++, j--) { 91 | char c = out[i]; 92 | out[i] = out[j]; 93 | out[j] = c; 94 | } 95 | 96 | *current = 0; 97 | return current - out; 98 | } 99 | 100 | void StringUtil::rtrim(std::string &source) { 101 | std::size_t pos = source.find_last_not_of(" \t\f\v\n\r"); 102 | if (pos != std::string::npos) { 103 | source.erase(pos + 1); 104 | } else { 105 | source.clear(); 106 | } 107 | } 108 | 109 | size_t StringUtil::strlcpy(char *dst, const char *src, size_t size) { 110 | strncpy(dst, src, size - 1); 111 | dst[size - 1] = '\0'; 112 | return strlen(src); 113 | } 114 | 115 | std::vector StringUtil::split(const std::string &source, 116 | char split) { 117 | return StringUtil::split(source, std::string{split}); 118 | } 119 | 120 | std::vector StringUtil::split(const std::string &source, 121 | const std::string &split, 122 | bool keep_empty_string) { 123 | std::vector ret; 124 | size_t last_index = 0; 125 | size_t next_index; 126 | 127 | if (split.empty()) { 128 | ret.emplace_back(source); 129 | return ret; 130 | } 131 | 132 | do { 133 | next_index = source.find(split, last_index); 134 | if (next_index == std::string::npos) { 135 | next_index = source.size(); 136 | } 137 | 138 | if (next_index != last_index || keep_empty_string) { 139 | ret.emplace_back(subspan(source, last_index, next_index)); 140 | } 141 | 142 | last_index = next_index + split.size(); 143 | } while (next_index != source.size()); 144 | 145 | return ret; 146 | } 147 | 148 | std::string StringUtil::join(const std::vector &source, 149 | const std::string &delimiter) { 150 | std::ostringstream buf; 151 | std::copy(source.begin(), source.end(), 152 | std::ostream_iterator(buf, delimiter.c_str())); 153 | std::string ret = buf.str(); 154 | // copy will always end with an extra delimiter, we remove it here. 155 | return ret.substr(0, ret.length() - delimiter.length()); 156 | } 157 | 158 | std::string StringUtil::subspan(const std::string &source, size_t start, 159 | size_t end) { 160 | return source.substr(start, end - start); 161 | } 162 | 163 | std::string StringUtil::escape(const std::string &source) { 164 | std::string ret; 165 | 166 | // Prevent unnecessary allocation by allocating 2x original size. 167 | ret.reserve(source.length() * 2); 168 | for (char c : source) { 169 | switch (c) { 170 | case '\r': 171 | ret += "\\r"; 172 | break; 173 | case '\n': 174 | ret += "\\n"; 175 | break; 176 | case '\t': 177 | ret += "\\t"; 178 | break; 179 | case '"': 180 | ret += "\\\""; 181 | break; 182 | default: 183 | ret += c; 184 | break; 185 | } 186 | } 187 | 188 | return ret; 189 | } 190 | 191 | bool StringUtil::endsWith(const std::string &source, const std::string &end) { 192 | if (source.length() < end.length()) { 193 | return false; 194 | } 195 | 196 | size_t start_position = source.length() - end.length(); 197 | return std::equal(source.begin() + start_position, source.end(), end.begin()); 198 | } 199 | 200 | bool StringUtil::startsWith(const char *source, const std::string &start, 201 | bool case_sensitive) { 202 | if (case_sensitive) { 203 | return strncmp(source, start.c_str(), start.size()) == 0; 204 | } else { 205 | return strncasecmp(source, start.c_str(), start.size()) == 0; 206 | } 207 | } 208 | 209 | void JsonUtil::mergeJsons(std::string &target, const std::string &source, 210 | const std::string &field_name) { 211 | rapidjson::Document target_doc, source_doc; 212 | target_doc.Parse(target.c_str()); 213 | source_doc.Parse(source.c_str()); 214 | 215 | target_doc.AddMember(rapidjson::StringRef(field_name.c_str()), source_doc, 216 | target_doc.GetAllocator()); 217 | 218 | rapidjson::StringBuffer sb; 219 | rapidjson::Writer w(sb); 220 | target_doc.Accept(w); 221 | target = sb.GetString(); 222 | } 223 | 224 | void JsonUtil::addArrayToJson(std::string &target, 225 | const std::vector &json_array, 226 | const std::string &field_name) { 227 | std::string stringified_json_array = "["; 228 | 229 | if (json_array.size() > 0) { 230 | stringified_json_array += json_array[0]; 231 | for (auto it = json_array.begin() + 1; it != json_array.end(); it++) { 232 | stringified_json_array += ","; 233 | stringified_json_array += *it; 234 | } 235 | } 236 | stringified_json_array += "]"; 237 | 238 | mergeJsons(target, stringified_json_array, field_name); 239 | } 240 | } // namespace zipkin 241 | -------------------------------------------------------------------------------- /zipkin/src/zipkin_core_constants.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "singleton.h" 6 | 7 | namespace zipkin { 8 | 9 | class ZipkinCoreConstantValues { 10 | public: 11 | const std::string CLIENT_SEND = "cs"; 12 | const std::string CLIENT_RECV = "cr"; 13 | const std::string SERVER_SEND = "ss"; 14 | const std::string SERVER_RECV = "sr"; 15 | 16 | const std::string HTTP_HOST = "http.host"; 17 | const std::string HTTP_METHOD = "http.method"; 18 | const std::string HTTP_PATH = "http.path"; 19 | const std::string HTTP_URL = "http.url"; 20 | const std::string HTTP_STATUS_CODE = "http.status_code"; 21 | const std::string HTTP_REQUEST_SIZE = "http.request.size"; 22 | const std::string HTTP_RESPONSE_SIZE = "http.response.size"; 23 | 24 | const std::string LOCAL_COMPONENT = "lc"; 25 | const std::string ERROR = "error"; 26 | const std::string CLIENT_ADDR = "ca"; 27 | const std::string SERVER_ADDR = "sa"; 28 | 29 | // Zipkin B3 headers 30 | const std::string X_B3_TRACE_ID = "X-B3-TraceId"; 31 | const std::string X_B3_SPAN_ID = "X-B3-SpanId"; 32 | const std::string X_B3_PARENT_SPAN_ID = "X-B3-ParentSpanId"; 33 | const std::string X_B3_SAMPLED = "X-B3-Sampled"; 34 | const std::string X_B3_FLAGS = "X-B3-Flags"; 35 | 36 | const std::string ALWAYS_SAMPLE = "1"; 37 | 38 | const std::string DEFAULT_COLLECTOR_ENDPOINT = "/api/v1/spans"; 39 | }; 40 | 41 | typedef ConstSingleton ZipkinCoreConstants; 42 | 43 | } // namespace zipkin 44 | -------------------------------------------------------------------------------- /zipkin/src/zipkin_core_types.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "zipkin_core_constants.h" 4 | #include "zipkin_json_field_names.h" 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | namespace zipkin { 12 | const std::string Endpoint::toJson() { 13 | rapidjson::StringBuffer s; 14 | rapidjson::Writer writer(s); 15 | writer.StartObject(); 16 | if (!address_.valid()) { 17 | writer.Key(ZipkinJsonFieldNames::get().ENDPOINT_IPV4.c_str()); 18 | writer.String(""); 19 | writer.Key(ZipkinJsonFieldNames::get().ENDPOINT_PORT.c_str()); 20 | writer.Uint(0); 21 | } else { 22 | if (address_.version() == IpVersion::v4) { 23 | // IPv4 24 | writer.Key(ZipkinJsonFieldNames::get().ENDPOINT_IPV4.c_str()); 25 | } else { 26 | // IPv6 27 | writer.Key(ZipkinJsonFieldNames::get().ENDPOINT_IPV6.c_str()); 28 | } 29 | writer.String(address_.addressAsString().c_str()); 30 | writer.Key(ZipkinJsonFieldNames::get().ENDPOINT_PORT.c_str()); 31 | writer.Uint(address_.port()); 32 | } 33 | writer.Key(ZipkinJsonFieldNames::get().ENDPOINT_SERVICE_NAME.c_str()); 34 | writer.String(service_name_.c_str()); 35 | writer.EndObject(); 36 | std::string json_string = s.GetString(); 37 | 38 | return json_string; 39 | } 40 | 41 | Annotation::Annotation(const Annotation &ann) { 42 | timestamp_ = ann.timestamp(); 43 | value_ = ann.value(); 44 | if (ann.isSetEndpoint()) { 45 | endpoint_ = ann.endpoint(); 46 | } 47 | } 48 | 49 | Annotation &Annotation::operator=(const Annotation &ann) { 50 | timestamp_ = ann.timestamp(); 51 | value_ = ann.value(); 52 | if (ann.isSetEndpoint()) { 53 | endpoint_ = ann.endpoint(); 54 | } 55 | 56 | return *this; 57 | } 58 | 59 | void Annotation::changeEndpointServiceName(const std::string &service_name) { 60 | if (endpoint_.valid()) { 61 | endpoint_.value().setServiceName(service_name); 62 | } 63 | } 64 | 65 | const std::string Annotation::toJson() { 66 | rapidjson::StringBuffer s; 67 | rapidjson::Writer writer(s); 68 | writer.StartObject(); 69 | writer.Key(ZipkinJsonFieldNames::get().ANNOTATION_TIMESTAMP.c_str()); 70 | writer.Uint64(timestamp_); 71 | writer.Key(ZipkinJsonFieldNames::get().ANNOTATION_VALUE.c_str()); 72 | writer.String(value_.c_str()); 73 | writer.EndObject(); 74 | 75 | std::string json_string = s.GetString(); 76 | 77 | if (endpoint_.valid()) { 78 | JsonUtil::mergeJsons( 79 | json_string, static_cast(endpoint_.value()).toJson(), 80 | ZipkinJsonFieldNames::get().ANNOTATION_ENDPOINT.c_str()); 81 | } 82 | 83 | return json_string; 84 | } 85 | 86 | const std::string BinaryAnnotation::toJson() { 87 | rapidjson::StringBuffer s; 88 | rapidjson::Writer writer(s); 89 | writer.StartObject(); 90 | writer.Key(ZipkinJsonFieldNames::get().BINARY_ANNOTATION_KEY.c_str()); 91 | writer.String(key_.c_str()); 92 | writer.Key(ZipkinJsonFieldNames::get().BINARY_ANNOTATION_VALUE.c_str()); 93 | switch (annotation_type_) { 94 | case STRING: 95 | writer.String(value_string_.c_str()); 96 | break; 97 | case BOOL: 98 | writer.Bool(value_bool_); 99 | break; 100 | case INT64: 101 | writer.Int64(value_int64_); 102 | break; 103 | case DOUBLE: 104 | writer.Double(value_double_); 105 | break; 106 | } 107 | 108 | if (annotation_type_ == INT64) { 109 | writer.Key(ZipkinJsonFieldNames::get().BINARY_ANNOTATION_TYPE.c_str()); 110 | writer.String( 111 | ZipkinJsonFieldNames::get().BINARY_ANNOTATION_TYPE_INT64.c_str()); 112 | } 113 | 114 | writer.EndObject(); 115 | 116 | std::string json_string = s.GetString(); 117 | 118 | if (endpoint_.valid()) { 119 | JsonUtil::mergeJsons( 120 | json_string, static_cast(endpoint_.value()).toJson(), 121 | ZipkinJsonFieldNames::get().BINARY_ANNOTATION_ENDPOINT.c_str()); 122 | } 123 | 124 | return json_string; 125 | } 126 | 127 | const std::string Span::EMPTY_HEX_STRING_ = "0000000000000000"; 128 | 129 | void Span::setServiceName(const std::string &service_name) { 130 | for (auto it = annotations_.begin(); it != annotations_.end(); it++) { 131 | it->changeEndpointServiceName(service_name); 132 | } 133 | } 134 | 135 | const std::string Span::toJson() { 136 | rapidjson::StringBuffer s; 137 | rapidjson::Writer writer(s); 138 | writer.StartObject(); 139 | writer.Key(ZipkinJsonFieldNames::get().SPAN_TRACE_ID.c_str()); 140 | writer.String(Hex::traceIdToHex(trace_id_).c_str()); 141 | writer.Key(ZipkinJsonFieldNames::get().SPAN_NAME.c_str()); 142 | writer.String(name_.c_str()); 143 | writer.Key(ZipkinJsonFieldNames::get().SPAN_ID.c_str()); 144 | writer.String(Hex::uint64ToHex(id_).c_str()); 145 | 146 | if (parent_id_.valid() && !parent_id_.value().empty()) { 147 | writer.Key(ZipkinJsonFieldNames::get().SPAN_PARENT_ID.c_str()); 148 | writer.String(Hex::traceIdToHex(parent_id_.value()).c_str()); 149 | } 150 | 151 | if (timestamp_.valid()) { 152 | writer.Key(ZipkinJsonFieldNames::get().SPAN_TIMESTAMP.c_str()); 153 | writer.Int64(timestamp_.value()); 154 | } 155 | 156 | if (duration_.valid()) { 157 | writer.Key(ZipkinJsonFieldNames::get().SPAN_DURATION.c_str()); 158 | writer.Int64(duration_.value()); 159 | } 160 | 161 | writer.EndObject(); 162 | 163 | std::string json_string = s.GetString(); 164 | 165 | std::vector annotation_json_vector; 166 | 167 | for (auto it = annotations_.begin(); it != annotations_.end(); it++) { 168 | annotation_json_vector.push_back(it->toJson()); 169 | } 170 | JsonUtil::addArrayToJson( 171 | json_string, annotation_json_vector, 172 | ZipkinJsonFieldNames::get().SPAN_ANNOTATIONS.c_str()); 173 | 174 | std::vector binary_annotation_json_vector; 175 | for (auto it = binary_annotations_.begin(); it != binary_annotations_.end(); 176 | it++) { 177 | binary_annotation_json_vector.push_back(it->toJson()); 178 | } 179 | JsonUtil::addArrayToJson( 180 | json_string, binary_annotation_json_vector, 181 | ZipkinJsonFieldNames::get().SPAN_BINARY_ANNOTATIONS.c_str()); 182 | 183 | return json_string; 184 | } 185 | 186 | void Span::finish() { 187 | if (auto t = tracer()) { 188 | if (this->isSampled()) { 189 | t->reportSpan(std::move(*this)); 190 | } 191 | } 192 | } 193 | 194 | void Span::setTag(const std::string &name, const std::string &value) { 195 | if (name.size() > 0 && value.size() > 0) { 196 | addBinaryAnnotation(BinaryAnnotation(name, value)); 197 | } 198 | } 199 | } // namespace zipkin 200 | -------------------------------------------------------------------------------- /zipkin/src/zipkin_http_transporter.cc: -------------------------------------------------------------------------------- 1 | #include "zipkin_http_transporter.h" 2 | 3 | #include "zipkin_core_constants.h" 4 | #include "zipkin_reporter_impl.h" 5 | 6 | #include 7 | #include 8 | 9 | namespace zipkin { 10 | static std::string getUrl(const char *collector_host, uint32_t collector_port) { 11 | return std::string{"http://"} + collector_host + ":" + 12 | std::to_string(collector_port) + 13 | ZipkinCoreConstants::get().DEFAULT_COLLECTOR_ENDPOINT; 14 | } 15 | 16 | ZipkinHttpTransporter::ZipkinHttpTransporter(const char *collector_host, 17 | uint32_t collector_port, 18 | std::chrono::milliseconds collector_timeout) { 19 | auto rcode = curl_easy_setopt(handle_, CURLOPT_URL, 20 | getUrl(collector_host, collector_port).c_str()); 21 | if (rcode != CURLE_OK) { 22 | throw CurlError{rcode}; 23 | } 24 | 25 | headers_.append("Content-Type: application/json"); 26 | rcode = curl_easy_setopt(handle_, CURLOPT_HTTPHEADER, 27 | static_cast(headers_)); 28 | if (rcode != CURLE_OK) { 29 | throw CurlError{rcode}; 30 | } 31 | 32 | rcode = curl_easy_setopt(handle_, CURLOPT_ERRORBUFFER, error_buffer_); 33 | if (rcode != CURLE_OK) { 34 | throw CurlError{rcode}; 35 | } 36 | 37 | rcode = curl_easy_setopt(handle_, CURLOPT_TIMEOUT_MS, collector_timeout.count()); 38 | if (rcode != CURLE_OK) { 39 | throw CurlError{rcode}; 40 | } 41 | } 42 | 43 | ZipkinHttpTransporter::~ZipkinHttpTransporter() {} 44 | 45 | void ZipkinHttpTransporter::transportSpans(SpanBuffer &spans) try { 46 | auto data = spans.toStringifiedJsonArray(); 47 | auto rcode = curl_easy_setopt(handle_, CURLOPT_POSTFIELDS, data.c_str()); 48 | if (rcode != CURLE_OK) { 49 | std::cerr << curl_easy_strerror(rcode) << '\n'; 50 | return; 51 | } 52 | rcode = curl_easy_perform(handle_); 53 | if (rcode != CURLE_OK) { 54 | std::cerr << error_buffer_ << '\n'; 55 | } 56 | } catch (const std::bad_alloc &) { 57 | // Drop spans 58 | } 59 | 60 | ReporterPtr makeHttpReporter(const char *collector_host, 61 | uint32_t collector_port, 62 | std::chrono::milliseconds collector_timeout, 63 | SteadyClock::duration reporting_period, 64 | size_t max_buffered_spans) try { 65 | std::unique_ptr transporter{ 66 | new ZipkinHttpTransporter{collector_host, collector_port, collector_timeout}}; 67 | std::unique_ptr reporter{new ReporterImpl{ 68 | std::move(transporter), reporting_period, max_buffered_spans}}; 69 | return reporter; 70 | } catch (const CurlError &error) { 71 | std::cerr << error.what() << '\n'; 72 | return nullptr; 73 | } 74 | } // namespace zipkin 75 | -------------------------------------------------------------------------------- /zipkin/src/zipkin_http_transporter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "transporter.h" 4 | #include "zipkin_reporter_impl.h" 5 | 6 | #include 7 | #include 8 | 9 | namespace zipkin { 10 | /** 11 | * Exception class used for CURL errors. 12 | */ 13 | class CurlError : public std::exception { 14 | public: 15 | CurlError(CURLcode code) : code_{code} {} 16 | 17 | const char *what() const noexcept override { 18 | return curl_easy_strerror(code_); 19 | } 20 | 21 | private: 22 | CURLcode code_; 23 | }; 24 | 25 | /** 26 | * RAII class to manage the initialization/deinitialization of the CURL 27 | * environment. 28 | */ 29 | class CurlEnvironment { 30 | public: 31 | CurlEnvironment() { curl_global_init(CURL_GLOBAL_ALL); } 32 | 33 | ~CurlEnvironment() { curl_global_cleanup(); } 34 | }; 35 | 36 | /** 37 | * RAII class to manage the allocation/deallocation of a CURL handle. 38 | */ 39 | class CurlHandle { 40 | public: 41 | CurlHandle() { handle_ = curl_easy_init(); } 42 | 43 | ~CurlHandle() { curl_easy_cleanup(handle_); } 44 | 45 | operator CURL *() { return handle_; } 46 | 47 | CURL *operator->() { return handle_; } 48 | 49 | private: 50 | CURL *handle_; 51 | }; 52 | 53 | /** 54 | * RAII class to manage the allocation/deallocation of a CURL SList 55 | */ 56 | class CurlSList { 57 | public: 58 | ~CurlSList() { 59 | if (list_) { 60 | curl_slist_free_all(list_); 61 | } 62 | } 63 | 64 | operator curl_slist *() { return list_; } 65 | 66 | void append(const char *s) { 67 | auto list_new = curl_slist_append(list_, s); 68 | if (!list_new) 69 | throw std::bad_alloc{}; 70 | list_ = list_new; 71 | } 72 | 73 | private: 74 | curl_slist *list_ = nullptr; 75 | }; 76 | 77 | /** 78 | * This class derives from the abstract zipkin::Transporter. It sends spans to 79 | * a zipkin collector via http. 80 | */ 81 | class ZipkinHttpTransporter : public Transporter { 82 | public: 83 | /** 84 | * Constructor. 85 | * 86 | * @param collector_host The host to use when sending spans to the Zipkin 87 | * service. 88 | * @param collector_port The port to use when sending spans to the Zipkin service. 89 | * @param collector_timeout Timeout for http requests 90 | * 91 | * Throws CurlError if the handle can't be initialized. 92 | */ 93 | ZipkinHttpTransporter(const char *collector_host, uint32_t collector_port, 94 | std::chrono::milliseconds collector_timeout = DEFAULT_TRANSPORT_TIMEOUT); 95 | 96 | /** 97 | * Destructor. 98 | */ 99 | ~ZipkinHttpTransporter(); 100 | 101 | /** 102 | * Implementation of zipkin::Transporter::transportSpans(). 103 | * 104 | * @param spans The spans to be transported. 105 | */ 106 | void transportSpans(SpanBuffer &spans) override; 107 | 108 | private: 109 | CurlEnvironment curl_environment_; 110 | CurlHandle handle_; 111 | CurlSList headers_; 112 | char error_buffer_[CURL_ERROR_SIZE]; 113 | }; 114 | } // namespace zipkin 115 | -------------------------------------------------------------------------------- /zipkin/src/zipkin_json_field_names.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "singleton.h" 6 | 7 | namespace zipkin { 8 | 9 | class ZipkinJsonFieldNameValues { 10 | public: 11 | const std::string SPAN_TRACE_ID = "traceId"; 12 | const std::string SPAN_PARENT_ID = "parentId"; 13 | const std::string SPAN_NAME = "name"; 14 | const std::string SPAN_ID = "id"; 15 | const std::string SPAN_TIMESTAMP = "timestamp"; 16 | const std::string SPAN_DURATION = "duration"; 17 | const std::string SPAN_ANNOTATIONS = "annotations"; 18 | const std::string SPAN_BINARY_ANNOTATIONS = "binaryAnnotations"; 19 | 20 | const std::string ANNOTATION_ENDPOINT = "endpoint"; 21 | const std::string ANNOTATION_TIMESTAMP = "timestamp"; 22 | const std::string ANNOTATION_VALUE = "value"; 23 | 24 | const std::string BINARY_ANNOTATION_ENDPOINT = "endpoint"; 25 | const std::string BINARY_ANNOTATION_KEY = "key"; 26 | const std::string BINARY_ANNOTATION_VALUE = "value"; 27 | const std::string BINARY_ANNOTATION_TYPE = "type"; 28 | const std::string BINARY_ANNOTATION_TYPE_INT64 = "I64"; 29 | 30 | const std::string ENDPOINT_SERVICE_NAME = "serviceName"; 31 | const std::string ENDPOINT_PORT = "port"; 32 | const std::string ENDPOINT_IPV4 = "ipv4"; 33 | const std::string ENDPOINT_IPV6 = "ipv6"; 34 | }; 35 | 36 | typedef ConstSingleton ZipkinJsonFieldNames; 37 | 38 | } // namespace zipkin 39 | -------------------------------------------------------------------------------- /zipkin/src/zipkin_reporter_impl.cc: -------------------------------------------------------------------------------- 1 | #include "zipkin_reporter_impl.h" 2 | #include 3 | 4 | namespace zipkin { 5 | 6 | ReporterImpl::ReporterImpl(TransporterPtr &&transporter, 7 | std::chrono::steady_clock::duration reporting_period, 8 | size_t max_buffered_spans) 9 | : transporter_{std::move(transporter)}, reporting_period_(reporting_period), 10 | max_buffered_spans_(max_buffered_spans), spans_{max_buffered_spans}, 11 | inflight_spans_{max_buffered_spans} { 12 | writer_ = std::thread(&ReporterImpl::writeReports, this); 13 | } 14 | 15 | ReporterImpl::~ReporterImpl() { 16 | makeWriterExit(); 17 | writer_.join(); 18 | } 19 | 20 | void ReporterImpl::reportSpan(const Span &span) { 21 | bool is_full; 22 | { 23 | std::lock_guard lock(write_mutex_); 24 | num_spans_reported_ += spans_.addSpan(span); 25 | is_full = spans_.pendingSpans() == max_buffered_spans_; 26 | } 27 | if (is_full) 28 | write_cond_.notify_one(); 29 | } 30 | 31 | bool ReporterImpl::flushWithTimeout( 32 | std::chrono::system_clock::duration timeout) { 33 | // Note: there is no effort made to speed up the flush when 34 | // requested, it simply waits for the regularly scheduled flush 35 | // operations to clear out all the presently pending data. 36 | std::unique_lock lock{write_mutex_}; 37 | 38 | auto num_spans_snapshot = num_spans_reported_; 39 | return write_cond_.wait_for(lock, timeout, [this, num_spans_snapshot] { 40 | return this->num_spans_flushed_ >= num_spans_snapshot; 41 | }); 42 | } 43 | 44 | void ReporterImpl::makeWriterExit() { 45 | std::lock_guard lock(write_mutex_); 46 | write_exit_ = true; 47 | write_cond_.notify_all(); 48 | } 49 | 50 | bool ReporterImpl::waitUntilNextReport(const SteadyTime &due_time) { 51 | std::unique_lock lock{write_mutex_}; 52 | write_cond_.wait_until(lock, due_time, [this] { return this->write_exit_; }); 53 | if (!write_exit_) { 54 | inflight_spans_.swap(spans_); 55 | } 56 | return !write_exit_; 57 | } 58 | 59 | void ReporterImpl::writeReports() { 60 | auto due_time = std::chrono::steady_clock::now() + reporting_period_; 61 | while (waitUntilNextReport(due_time)) { 62 | if (inflight_spans_.pendingSpans() > 0) { 63 | transporter_->transportSpans(inflight_spans_); 64 | num_spans_flushed_ += inflight_spans_.pendingSpans(); 65 | inflight_spans_.clear(); 66 | 67 | // If the buffer capacity has been changed, this is the place to resize 68 | // it. 69 | if (inflight_spans_.spanCapacity() != max_buffered_spans_) { 70 | inflight_spans_.allocateBuffer(max_buffered_spans_); 71 | } 72 | write_cond_.notify_all(); 73 | } 74 | auto now = std::chrono::steady_clock::now(); 75 | due_time += reporting_period_; 76 | if (due_time < now) 77 | due_time = now; 78 | } 79 | } 80 | } // namespace zipkin 81 | -------------------------------------------------------------------------------- /zipkin/src/zipkin_reporter_impl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "transporter.h" 11 | #include 12 | 13 | namespace zipkin { 14 | /** 15 | * This class derives from the abstract zipkin::Reporter. It buffers spans and 16 | * relies on a Transporter to send spans to Zipkin. 17 | * 18 | * Up to `???` will be buffered. Spans are flushed 19 | * (sent to Zipkin) either when the buffer is full, or when a timer, set to 20 | * `????`, expires, whichever happens first. 21 | * 22 | * The default values for the runtime parameters are 5 spans and 5000ms. 23 | */ 24 | class ReporterImpl : public Reporter { 25 | public: 26 | /** 27 | * Constructor. 28 | * 29 | * @param transporter The Transporter to be associated with the reporter. 30 | */ 31 | ReporterImpl( 32 | TransporterPtr &&transporter, 33 | SteadyClock::duration reporting_period = DEFAULT_REPORTING_PERIOD, 34 | size_t max_buffered_spans = DEFAULT_SPAN_BUFFER_SIZE); 35 | 36 | /** 37 | * Destructor. 38 | */ 39 | ~ReporterImpl(); 40 | 41 | /** 42 | * Implementation of zipkin::Reporter::reportSpan(). 43 | * 44 | * Buffers the given span and calls flushSpans() if the buffer is full. 45 | * 46 | * @param span The span to be buffered. 47 | */ 48 | void reportSpan(const Span &span) override; 49 | 50 | bool flushWithTimeout(std::chrono::system_clock::duration timeout) override; 51 | 52 | private: 53 | TransporterPtr transporter_; 54 | 55 | std::mutex write_mutex_; 56 | std::condition_variable write_cond_; 57 | SteadyClock::duration reporting_period_; 58 | size_t max_buffered_spans_; 59 | 60 | bool write_exit_ = false; 61 | std::thread writer_; 62 | int64_t num_spans_reported_ = 0; 63 | std::atomic num_spans_flushed_{0}; 64 | SpanBuffer spans_; 65 | SpanBuffer inflight_spans_; 66 | 67 | void makeWriterExit(); 68 | bool waitUntilNextReport(const SteadyTime &due_time); 69 | void writeReports(); 70 | }; 71 | } // namespace zipkin 72 | -------------------------------------------------------------------------------- /zipkin/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(hex_test hex_test.cc) 2 | add_test(hex_test hex_test) 3 | target_link_libraries(hex_test zipkin) 4 | -------------------------------------------------------------------------------- /zipkin/test/hex_test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define CATCH_CONFIG_MAIN 7 | #include 8 | using namespace zipkin; 9 | 10 | TEST_CASE("hex") { 11 | CHECK(Hex::hexToUint64("1").value() == 1); 12 | CHECK(Hex::hexToUint64("a").value() == 10); 13 | CHECK(Hex::hexToUint64("11").value() == 17); 14 | CHECK(Hex::hexToUint64("011").value() == 17); 15 | CHECK(Hex::hexToUint64("0011").value() == 17); 16 | CHECK(Hex::hexToUint64("100").value() == 256); 17 | CHECK(Hex::hexToUint64("1000").value() == 4096); 18 | 19 | // Check against random 64-bit integers. 20 | for (int i = 0; i < 10; ++i) { 21 | auto id = RandomUtil::generateId(); 22 | auto s = Hex::uint64ToHex(id); 23 | auto id_maybe = Hex::hexToUint64(s); 24 | CHECK(id_maybe.valid()); 25 | CHECK(id_maybe.value() == id); 26 | 27 | auto trace_id_maybe = Hex::hexToTraceId(s); 28 | CHECK(trace_id_maybe.valid()); 29 | CHECK(trace_id_maybe.value().low() == id); 30 | CHECK(trace_id_maybe.value().high() == 0); 31 | } 32 | 33 | // Check against random 128-bit Trace IDs. 34 | for (int i = 0; i < 10; ++i) { 35 | auto high = RandomUtil::generateId(); 36 | auto low = RandomUtil::generateId(); 37 | auto trace_id = TraceId{high, low}; 38 | auto s = Hex::traceIdToHex(trace_id); 39 | auto trace_id_maybe = Hex::hexToTraceId(s); 40 | CHECK(trace_id_maybe.valid()); 41 | CHECK(trace_id_maybe.value().low() == low); 42 | CHECK(trace_id_maybe.value().high() == high); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /zipkin_opentracing/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_path(OPENTRACING_INCLUDE_DIR NAMES opentracing/tracer.h) 2 | find_library(OPENTRACING_LIB opentracing) 3 | 4 | include_directories(SYSTEM ${OPENTRACING_INCLUDE_DIR}) 5 | 6 | set(EMBED_CONFIGURATION_SCHEMA_OUTPUT_FILE 7 | ${CMAKE_CURRENT_BINARY_DIR}/tracer_configuration_schema.cpp) 8 | add_custom_command( 9 | OUTPUT ${EMBED_CONFIGURATION_SCHEMA_OUTPUT_FILE} 10 | COMMAND embedfile tracer_configuration_schema ${CMAKE_CURRENT_SOURCE_DIR}/tracer_configuration.schema.json 11 | DEPENDS tracer_configuration.schema.json 12 | ) 13 | 14 | install(DIRECTORY include/zipkin 15 | COMPONENT DEVEL 16 | DESTINATION include) 17 | set(ZIPKIN_OPENTRACING_SRCS src/utility.cc 18 | src/propagation.cc 19 | src/dynamic_load.cc 20 | src/tracer_factory.cc 21 | src/opentracing.cc 22 | src/sampling.cc 23 | ${EMBED_CONFIGURATION_SCHEMA_OUTPUT_FILE}) 24 | 25 | 26 | if (BUILD_SHARED_LIBS) 27 | add_library(zipkin_opentracing SHARED ${ZIPKIN_OPENTRACING_SRCS}) 28 | target_link_libraries(zipkin_opentracing ${OPENTRACING_LIB} zipkin) 29 | set_target_properties(zipkin_opentracing PROPERTIES VERSION ${ZIPKIN_VERSION_STRING} 30 | SOVERSION ${ZIPKIN_VERSION_MAJOR}) 31 | install(TARGETS zipkin_opentracing 32 | COMPONENT DIST 33 | LIBRARY DESTINATION lib) 34 | endif() 35 | 36 | if (BUILD_STATIC_LIBS) 37 | add_library(zipkin_opentracing-static STATIC ${ZIPKIN_OPENTRACING_SRCS}) 38 | set_target_properties(zipkin_opentracing-static PROPERTIES OUTPUT_NAME zipkin_opentracing) 39 | target_link_libraries(zipkin_opentracing-static ${OPENTRACING_LIB} zipkin) 40 | install(TARGETS zipkin_opentracing-static 41 | ARCHIVE DESTINATION lib) 42 | endif() 43 | 44 | if (BUILD_PLUGIN) 45 | file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/export.map 46 | "{ global: OpenTracingMakeTracerFactory; local: *; };") 47 | add_library(zipkin_opentracing_plugin MODULE ${ZIPKIN_OPENTRACING_SRCS}) 48 | target_link_libraries(zipkin_opentracing_plugin ${OPENTRACING_LIB} 49 | zipkin-plugin-static 50 | -static-libgcc 51 | -static-libstdc++ 52 | -Wl,--version-script=${CMAKE_CURRENT_BINARY_DIR}/export.map) 53 | install(TARGETS zipkin_opentracing_plugin 54 | LIBRARY DESTINATION lib) 55 | endif() 56 | 57 | 58 | if(BUILD_SHARED_LIBS AND BUILD_TESTING) 59 | add_subdirectory(example) 60 | add_subdirectory(test) 61 | endif() 62 | -------------------------------------------------------------------------------- /zipkin_opentracing/example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(tutorial tutorial.cc) 2 | target_link_libraries(tutorial ${CURL_LIBRARIES} ${OPENTRACING_LIB} zipkin zipkin_opentracing) 3 | -------------------------------------------------------------------------------- /zipkin_opentracing/example/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 | using opentracing::expected; 9 | using opentracing::string_view; 10 | using opentracing::TextMapReader; 11 | using opentracing::TextMapWriter; 12 | 13 | class TextMapCarrier : public TextMapReader, public TextMapWriter { 14 | public: 15 | TextMapCarrier(std::unordered_map &text_map) 16 | : text_map_(text_map) {} 17 | 18 | expected Set(string_view key, string_view value) const override { 19 | text_map_[key] = value; 20 | return {}; 21 | } 22 | 23 | expected ForeachKey( 24 | std::function(string_view key, string_view value)> f) 25 | const override { 26 | for (const auto &key_value : text_map_) { 27 | auto result = f(key_value.first, key_value.second); 28 | if (!result) 29 | return result; 30 | } 31 | return {}; 32 | } 33 | 34 | private: 35 | std::unordered_map &text_map_; 36 | }; 37 | 38 | #endif // LIGHTSTEP_TEXT_MAP_CARRIER 39 | -------------------------------------------------------------------------------- /zipkin_opentracing/example/tutorial.cc: -------------------------------------------------------------------------------- 1 | #include "text_map_carrier.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace zipkin; 7 | using namespace opentracing; 8 | 9 | int main() { 10 | ZipkinOtTracerOptions options; 11 | options.service_name = "Tutorial"; 12 | auto tracer = makeZipkinOtTracer(options); 13 | assert(tracer); 14 | 15 | auto parent_span = tracer->StartSpan("parent"); 16 | assert(parent_span); 17 | 18 | // Create a child span. 19 | { 20 | auto child_span = 21 | tracer->StartSpan("childA", {ChildOf(&parent_span->context())}); 22 | assert(child_span); 23 | 24 | // Set a simple tag. 25 | child_span->SetTag("simple tag", 123); 26 | 27 | // Set a complex tag. 28 | child_span->SetTag("complex tag", 29 | Values{123, Dictionary{{"abc", 123}, {"xyz", 4.0}}}); 30 | 31 | // Log simple values. 32 | child_span->Log({{"event", "simple log"}, {"abc", 123}}); 33 | 34 | // Log complex values. 35 | child_span->Log({{"event", "complex log"}, 36 | {"data", Dictionary{{"a", 1}, {"b", Values{1, 2}}}}}); 37 | 38 | child_span->Finish(); 39 | } 40 | 41 | // Create a follows from span. 42 | { 43 | auto child_span = 44 | tracer->StartSpan("childB", {FollowsFrom(&parent_span->context())}); 45 | 46 | // child_span's destructor will finish the span if not done so explicitly. 47 | } 48 | 49 | // Use custom timestamps. 50 | { 51 | auto t1 = SystemClock::now(); 52 | auto t2 = SteadyClock::now(); 53 | auto span = tracer->StartSpan( 54 | "useCustomTimestamps", 55 | {ChildOf(&parent_span->context()), StartTimestamp(t1)}); 56 | assert(span); 57 | span->Finish({FinishTimestamp(t2)}); 58 | } 59 | 60 | // Extract and Inject a span context. 61 | { 62 | std::unordered_map text_map; 63 | TextMapCarrier carrier(text_map); 64 | auto err = tracer->Inject(parent_span->context(), carrier); 65 | assert(err); 66 | auto span_context_maybe = tracer->Extract(carrier); 67 | assert(span_context_maybe); 68 | auto span = tracer->StartSpan("propagationSpan", 69 | {ChildOf(span_context_maybe->get())}); 70 | } 71 | 72 | // You get an error when trying to extract a corrupt span. 73 | { 74 | std::unordered_map text_map = { 75 | {"x-b3-traceid", "123"}}; 76 | TextMapCarrier carrier(text_map); 77 | auto err = tracer->Extract(carrier); 78 | assert(!err); 79 | assert(err.error() == span_context_corrupted_error); 80 | // How to get a readable message from the error. 81 | std::cout << "Example error message: \"" << err.error().message() << "\"\n"; 82 | } 83 | 84 | // span.kind can be used to control whether Zipkin's cs/cr or sr/ss anotations 85 | // are set. 86 | { 87 | auto client_span = tracer->StartSpan("tutorial.clientSpan"); 88 | assert(client_span); 89 | client_span->SetTag("span.kind", "client"); 90 | auto server_span = tracer->StartSpan("tutorial.serverSpan", 91 | {ChildOf(&client_span->context())}); 92 | assert(server_span); 93 | server_span->SetTag("span.kind", "server"); 94 | server_span->Finish(); 95 | client_span->Finish(); 96 | } 97 | 98 | parent_span->Finish(); 99 | tracer->Close(); 100 | 101 | return 0; 102 | } 103 | -------------------------------------------------------------------------------- /zipkin_opentracing/include/zipkin/opentracing.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace zipkin { 8 | struct ZipkinOtTracerOptions { 9 | std::string collector_host = "localhost"; 10 | uint32_t collector_port = 9411; 11 | std::chrono::milliseconds collector_timeout = DEFAULT_TRANSPORT_TIMEOUT; 12 | SteadyClock::duration reporting_period = DEFAULT_REPORTING_PERIOD; 13 | size_t max_buffered_spans = DEFAULT_SPAN_BUFFER_SIZE; 14 | double sample_rate = 1.0; 15 | 16 | std::string service_name; 17 | IpAddress service_address; 18 | }; 19 | 20 | std::shared_ptr 21 | makeZipkinOtTracer(const ZipkinOtTracerOptions &options); 22 | 23 | std::shared_ptr 24 | makeZipkinOtTracer(const ZipkinOtTracerOptions &options, 25 | std::unique_ptr &&reporter); 26 | 27 | } // namespace zipkin 28 | -------------------------------------------------------------------------------- /zipkin_opentracing/src/dynamic_load.cc: -------------------------------------------------------------------------------- 1 | #include "tracer_factory.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static int OpenTracingMakeTracerFactoryFunction( 8 | const char *opentracing_version, const char *opentracing_abi_version, 9 | const void **error_category, void *error_message, 10 | void **tracer_factory) try { 11 | if (opentracing_version == nullptr || opentracing_abi_version == nullptr || 12 | error_message == nullptr || error_category == nullptr || 13 | tracer_factory == nullptr) { 14 | fprintf(stderr, 15 | "`opentracing_version`, `opentracing_abi_version`, " 16 | "`error_message`, `error_category`, and `tracer_factory` must be " 17 | "non-null.\n"); 18 | std::terminate(); 19 | } 20 | 21 | if (std::strcmp(opentracing_abi_version, OPENTRACING_ABI_VERSION) != 0) { 22 | *error_category = 23 | static_cast(&opentracing::dynamic_load_error_category()); 24 | auto &message = *static_cast(error_message); 25 | message = "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 zipkin::OtTracerFactory{}; 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 | -------------------------------------------------------------------------------- /zipkin_opentracing/src/propagation.cc: -------------------------------------------------------------------------------- 1 | #include "propagation.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace ot = opentracing; 9 | 10 | namespace zipkin { 11 | #define PREFIX_TRACER_STATE "x-b3-" 12 | // Note: these constants are a convention of the OpenTracing basictracers. 13 | const ot::string_view prefix_baggage = "ot-baggage-"; 14 | 15 | const int tracer_state_required_field_count = 2; 16 | const ot::string_view zipkin_trace_id = PREFIX_TRACER_STATE "traceid"; 17 | const ot::string_view zipkin_span_id = PREFIX_TRACER_STATE "spanid"; 18 | const ot::string_view zipkin_parent_span_id = 19 | PREFIX_TRACER_STATE "parentspanid"; 20 | const ot::string_view zipkin_sampled = PREFIX_TRACER_STATE "sampled"; 21 | const ot::string_view zipkin_flags = PREFIX_TRACER_STATE "flags"; 22 | #undef PREFIX_TRACER_STATE 23 | 24 | static bool keyCompare(ot::string_view lhs, ot::string_view rhs) { 25 | return lhs.length() == rhs.length() && 26 | std::equal( 27 | std::begin(lhs), std::end(lhs), std::begin(rhs), 28 | [](char a, char b) { return std::tolower(a) == std::tolower(b); }); 29 | } 30 | 31 | // Follows the rules of the go function strconv.ParseBool so as to interoperate 32 | // with the other Zipkin tracing libraries. 33 | // See https://golang.org/pkg/strconv/#ParseBool 34 | static bool parseBool(ot::string_view s, bool &result) { 35 | if (s == "1" || s == "t" || s == "T" || s == "TRUE" || s == "true" || 36 | s == "True") { 37 | result = true; 38 | return true; 39 | } 40 | if (s == "0" || s == "f" || s == "F" || s == "FALSE" || s == "false" || 41 | s == "False") { 42 | result = false; 43 | return true; 44 | } 45 | return false; 46 | } 47 | 48 | opentracing::expected 49 | injectSpanContext(std::ostream &carrier, 50 | const zipkin::SpanContext &span_context, 51 | const std::unordered_map &baggage) { 52 | return ot::make_unexpected(ot::invalid_carrier_error); 53 | } 54 | 55 | opentracing::expected 56 | injectSpanContext(const opentracing::TextMapWriter &carrier, 57 | const zipkin::SpanContext &span_context, 58 | const std::unordered_map &baggage) { 59 | auto result = carrier.Set(zipkin_trace_id, span_context.traceIdAsHexString()); 60 | if (!result) { 61 | return result; 62 | } 63 | result = carrier.Set(zipkin_span_id, span_context.idAsHexString()); 64 | if (!result) { 65 | return result; 66 | } 67 | result = carrier.Set(zipkin_sampled, span_context.isSampled() ? "1" : "0"); 68 | if (!result) { 69 | return result; 70 | } 71 | if (span_context.isSetParentId()) { 72 | result = 73 | carrier.Set(zipkin_parent_span_id, span_context.parentIdAsHexString()); 74 | if (!result) { 75 | return result; 76 | } 77 | } 78 | result = carrier.Set(zipkin_flags, 79 | std::to_string(span_context.flags() & debug_flag)); 80 | if (!result) { 81 | return result; 82 | } 83 | std::string baggage_key = prefix_baggage; 84 | for (const auto &baggage_item : baggage) { 85 | baggage_key.replace(std::begin(baggage_key) + prefix_baggage.size(), 86 | std::end(baggage_key), baggage_item.first); 87 | result = carrier.Set(baggage_key, baggage_item.second); 88 | if (!result) { 89 | return result; 90 | } 91 | } 92 | return result; 93 | } 94 | 95 | opentracing::expected> 96 | extractSpanContext(std::istream &carrier, 97 | std::unordered_map &baggage) { 98 | return ot::make_unexpected(ot::invalid_carrier_error); 99 | } 100 | 101 | opentracing::expected> 102 | extractSpanContext(const opentracing::TextMapReader &carrier, 103 | std::unordered_map &baggage) { 104 | int required_field_count = 0; 105 | TraceId trace_id; 106 | Optional parent_id; 107 | uint64_t span_id; 108 | flags_t flags = 0; 109 | auto result = carrier.ForeachKey( 110 | [&](ot::string_view key, ot::string_view value) -> ot::expected { 111 | if (keyCompare(key, zipkin_trace_id)) { 112 | auto trace_id_maybe = Hex::hexToTraceId(value); 113 | if (!trace_id_maybe.valid()) { 114 | return ot::make_unexpected(ot::span_context_corrupted_error); 115 | } 116 | trace_id = trace_id_maybe.value(); 117 | ++required_field_count; 118 | } else if (keyCompare(key, zipkin_span_id)) { 119 | auto span_id_maybe = Hex::hexToUint64(value); 120 | if (!span_id_maybe.valid()) { 121 | return ot::make_unexpected(ot::span_context_corrupted_error); 122 | } 123 | span_id = span_id_maybe.value(); 124 | ++required_field_count; 125 | } else if (keyCompare(key, zipkin_flags)) { 126 | auto value_str = std::string{value}; 127 | flags_t f; 128 | if (!StringUtil::atoull(value_str.c_str(), f)) { 129 | return ot::make_unexpected(ot::span_context_corrupted_error); 130 | } 131 | // Only use the debug flag. 132 | flags |= f & debug_flag; 133 | } else if (keyCompare(key, zipkin_sampled)) { 134 | bool sampled; 135 | if (!parseBool(value, sampled)) { 136 | return ot::make_unexpected(ot::span_context_corrupted_error); 137 | } 138 | if (sampled) { 139 | flags |= sampled_flag; 140 | } 141 | } else if (keyCompare(key, zipkin_parent_span_id)) { 142 | parent_id = Hex::hexToTraceId(value); 143 | if (!parent_id.valid()) { 144 | return ot::make_unexpected(ot::span_context_corrupted_error); 145 | } 146 | } else if (key.length() > prefix_baggage.size() && 147 | keyCompare( 148 | ot::string_view{key.data(), prefix_baggage.size()}, 149 | prefix_baggage)) { 150 | baggage.emplace(std::string{std::begin(key) + prefix_baggage.size(), 151 | std::end(key)}, 152 | value); 153 | } 154 | return {}; 155 | }); 156 | if (required_field_count == 0) { 157 | return {}; 158 | } 159 | if (required_field_count != tracer_state_required_field_count) { 160 | return ot::make_unexpected(ot::span_context_corrupted_error); 161 | } 162 | return Optional{ 163 | SpanContext{trace_id, span_id, parent_id, flags}}; 164 | } 165 | } // namespace zipkin 166 | -------------------------------------------------------------------------------- /zipkin_opentracing/src/propagation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace zipkin { 8 | opentracing::expected 9 | injectSpanContext(std::ostream &carrier, 10 | const zipkin::SpanContext &span_context, 11 | const std::unordered_map &baggage); 12 | 13 | opentracing::expected 14 | injectSpanContext(const opentracing::TextMapWriter &carrier, 15 | const zipkin::SpanContext &span_context, 16 | const std::unordered_map &baggage); 17 | 18 | opentracing::expected> 19 | extractSpanContext(std::istream &carrier, 20 | std::unordered_map &baggage); 21 | 22 | opentracing::expected> 23 | extractSpanContext(const opentracing::TextMapReader &carrier, 24 | std::unordered_map &baggage); 25 | } // namespace zipkin 26 | -------------------------------------------------------------------------------- /zipkin_opentracing/src/sampling.cc: -------------------------------------------------------------------------------- 1 | #include "sampling.h" 2 | #include 3 | #include 4 | 5 | namespace zipkin { 6 | std::mt19937_64 &getTlsRandomEngine(); 7 | 8 | bool ProbabilisticSampler::ShouldSample() { 9 | std::bernoulli_distribution dist(sample_rate_); 10 | return dist(getTlsRandomEngine()); 11 | } 12 | } // namespace zipkin 13 | -------------------------------------------------------------------------------- /zipkin_opentracing/src/sampling.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace zipkin { 6 | class Sampler { 7 | public: 8 | virtual ~Sampler() = default; 9 | virtual bool ShouldSample() = 0; 10 | }; 11 | 12 | class ProbabilisticSampler : public Sampler { 13 | public: 14 | explicit ProbabilisticSampler(double sample_rate) 15 | : sample_rate_(std::max(0.0, std::min(sample_rate, 1.0))){}; 16 | bool ShouldSample() override; 17 | 18 | private: 19 | double sample_rate_; 20 | }; 21 | 22 | typedef std::unique_ptr SamplerPtr; 23 | } // namespace zipkin -------------------------------------------------------------------------------- /zipkin_opentracing/src/tracer_factory.cc: -------------------------------------------------------------------------------- 1 | #include "tracer_factory.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace zipkin { 9 | 10 | extern const unsigned char tracer_configuration_schema[]; 11 | extern const int tracer_configuration_schema_size; 12 | 13 | opentracing::expected> 14 | OtTracerFactory::MakeTracer(const char *configuration, 15 | std::string &error_message) const noexcept try { 16 | static rapidjson::SchemaDocument schema = [] { 17 | rapidjson::Document document; 18 | document.Parse(reinterpret_cast(tracer_configuration_schema), 19 | tracer_configuration_schema_size); 20 | if (document.HasParseError()) { 21 | std::cerr << "Internal Error: Configuration schema is invalid.\n"; 22 | std::terminate(); 23 | } 24 | return rapidjson::SchemaDocument{document}; 25 | }(); 26 | 27 | rapidjson::Document document; 28 | rapidjson::ParseResult parse_result = document.Parse(configuration); 29 | if (!parse_result) { 30 | error_message = std::string{"JSON parse error: "} + 31 | rapidjson::GetParseError_En(parse_result.Code()) + " (" + 32 | std::to_string(parse_result.Offset()) + ")"; 33 | return opentracing::make_unexpected(opentracing::configuration_parse_error); 34 | } 35 | 36 | rapidjson::SchemaValidator validator{schema}; 37 | if (!document.Accept(validator)) { 38 | error_message = "Configuration is invalid."; 39 | return opentracing::make_unexpected( 40 | opentracing::invalid_configuration_error); 41 | } 42 | 43 | ZipkinOtTracerOptions options; 44 | options.service_name = document["service_name"].GetString(); 45 | if (document.HasMember("service_address")) { 46 | options.service_address = 47 | IpAddress{IpVersion::v4, document["service_address"].GetString()}; 48 | } 49 | if (document.HasMember("collector_host")) { 50 | options.collector_host = document["collector_host"].GetString(); 51 | } 52 | if (document.HasMember("collector_port")) { 53 | options.collector_port = document["collector_port"].GetInt(); 54 | } 55 | if (document.HasMember("collector_timeout")) { 56 | options.collector_timeout = 57 | std::chrono::milliseconds{document["collector_timeout"].GetInt()}; 58 | } 59 | if (document.HasMember("reporting_period")) { 60 | options.reporting_period = 61 | std::chrono::microseconds{document["reporting_period"].GetInt()}; 62 | } 63 | if (document.HasMember("max_buffered_spans")) { 64 | options.max_buffered_spans = document["max_buffered_spans"].GetInt(); 65 | } 66 | if (document.HasMember("sample_rate")) { 67 | options.sample_rate = document["sample_rate"].GetDouble(); 68 | } 69 | return makeZipkinOtTracer(options); 70 | } catch (const std::bad_alloc &) { 71 | return opentracing::make_unexpected( 72 | std::make_error_code(std::errc::not_enough_memory)); 73 | } 74 | } // namespace zipkin 75 | -------------------------------------------------------------------------------- /zipkin_opentracing/src/tracer_factory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace zipkin { 6 | class OtTracerFactory : public opentracing::TracerFactory { 7 | public: 8 | opentracing::expected> 9 | MakeTracer(const char *configuration, std::string &error_message) const 10 | noexcept override; 11 | }; 12 | } // namespace zipkin 13 | -------------------------------------------------------------------------------- /zipkin_opentracing/src/utility.cc: -------------------------------------------------------------------------------- 1 | #include "utility.h" 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace opentracing; 7 | 8 | namespace zipkin { 9 | using JsonWriter = rapidjson::Writer; 10 | 11 | static bool toJson(JsonWriter &writer, const Value &value); 12 | 13 | namespace { 14 | struct JsonValueVisitor { 15 | JsonWriter &writer; 16 | bool result; 17 | 18 | void operator()(bool value) { result = writer.Bool(value); } 19 | 20 | void operator()(double value) { result = writer.Double(value); } 21 | 22 | void operator()(int64_t value) { result = writer.Int64(value); } 23 | 24 | void operator()(uint64_t value) { result = writer.Uint64(value); } 25 | 26 | void operator()(const std::string &s) { 27 | result = writer.String(s.data(), static_cast(s.size())); 28 | } 29 | 30 | void operator()(std::nullptr_t) { result = writer.Null(); } 31 | 32 | void operator()(const char *s) { result = writer.String(s); } 33 | 34 | void operator()(const Values &values) { 35 | if (!(result = writer.StartArray())) { 36 | return; 37 | } 38 | for (const auto &value : values) { 39 | if (!(result = toJson(writer, value))) { 40 | return; 41 | } 42 | } 43 | result = writer.EndArray(); 44 | } 45 | 46 | void operator()(const Dictionary &dictionary) { 47 | if (!(result = writer.StartObject())) { 48 | return; 49 | } 50 | for (const auto &key_value : dictionary) { 51 | if (!(result = 52 | writer.Key(key_value.first.data(), 53 | static_cast(key_value.first.size())))) { 54 | return; 55 | } 56 | if (!(result = toJson(writer, key_value.second))) { 57 | return; 58 | } 59 | } 60 | result = writer.EndObject(); 61 | } 62 | }; 63 | } // anonymous namespace 64 | 65 | static bool toJson(JsonWriter &writer, const Value &value) { 66 | JsonValueVisitor value_visitor{writer, true}; 67 | apply_visitor(value_visitor, value); 68 | return value_visitor.result; 69 | } 70 | 71 | static std::string toJson(const Value &value) { 72 | rapidjson::StringBuffer buffer; 73 | JsonWriter writer(buffer); 74 | if (!toJson(writer, value)) { 75 | return {}; 76 | } 77 | return buffer.GetString(); 78 | } 79 | 80 | namespace { 81 | struct ValueVisitor { 82 | BinaryAnnotation &annotation; 83 | const Value &original_value; 84 | 85 | void operator()(bool value) const { 86 | annotation.setValue(std::to_string(value)); 87 | } 88 | 89 | void operator()(double value) const { 90 | annotation.setValue(std::to_string(value)); 91 | } 92 | 93 | void operator()(int64_t value) const { 94 | annotation.setValue(std::to_string(value)); 95 | } 96 | 97 | void operator()(uint64_t value) const { 98 | // There's no uint64_t value type so cast to an int64_t. 99 | annotation.setValue(std::to_string(value)); 100 | } 101 | 102 | void operator()(const std::string &s) const { annotation.setValue(s); } 103 | 104 | void operator()(std::nullptr_t) const { annotation.setValue("0"); } 105 | 106 | void operator()(const char *s) const { annotation.setValue(std::string{s}); } 107 | 108 | void operator()(const Values & /*unused*/) const { 109 | annotation.setValue(toJson(original_value)); 110 | } 111 | 112 | void operator()(const Dictionary & /*unused*/) const { 113 | annotation.setValue(toJson(original_value)); 114 | } 115 | }; 116 | } // anonymous namespace 117 | 118 | BinaryAnnotation toBinaryAnnotation(string_view key, const Value &value) { 119 | BinaryAnnotation annotation; 120 | annotation.setKey(key); 121 | ValueVisitor value_visitor{annotation, value}; 122 | apply_visitor(value_visitor, value); 123 | return annotation; 124 | } 125 | } // namespace zipkin 126 | -------------------------------------------------------------------------------- /zipkin_opentracing/src/utility.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace zipkin { 8 | BinaryAnnotation toBinaryAnnotation(opentracing::string_view key, 9 | const opentracing::Value &value); 10 | } // namespace zipkin 11 | -------------------------------------------------------------------------------- /zipkin_opentracing/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | macro(_zipkin_ot_test TEST_NAME) 2 | add_executable(${TEST_NAME} ${ARGN}) 3 | target_link_libraries(${TEST_NAME} ${CURL_LIBRARIES} 4 | ${OPENTRACING_LIB} 5 | zipkin 6 | zipkin_opentracing) 7 | add_test(${TEST_NAME} ${TEST_NAME}) 8 | endmacro() 9 | 10 | _zipkin_ot_test(ot_tracer_test ot_tracer_test.cc) 11 | _zipkin_ot_test(ot_tracer_factory_test ot_tracer_factory_test.cc) 12 | -------------------------------------------------------------------------------- /zipkin_opentracing/test/in_memory_reporter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace zipkin { 8 | // InMemoryReporter is used for testing only. 9 | class InMemoryReporter : public Reporter { 10 | public: 11 | void reportSpan(const Span &span) override { 12 | std::lock_guard lock_guard(mutex_); 13 | spans_.emplace_back(std::move(span)); 14 | } 15 | 16 | std::vector spans() const { 17 | std::lock_guard lock_guard(mutex_); 18 | return spans_; 19 | } 20 | 21 | size_t size() const { 22 | std::lock_guard lock_guard(mutex_); 23 | return spans_.size(); 24 | } 25 | 26 | Span top() const { 27 | std::lock_guard lock_guard(mutex_); 28 | if (spans_.empty()) 29 | throw std::runtime_error("no spans"); 30 | return spans_.back(); 31 | } 32 | 33 | private: 34 | mutable std::mutex mutex_; 35 | std::vector spans_; 36 | }; 37 | } // namespace zipkin 38 | -------------------------------------------------------------------------------- /zipkin_opentracing/test/ot_tracer_factory_test.cc: -------------------------------------------------------------------------------- 1 | #include "../src/tracer_factory.h" 2 | 3 | #define CATCH_CONFIG_MAIN 4 | #include 5 | using namespace zipkin; 6 | namespace ot = opentracing; 7 | 8 | TEST_CASE("OtTracerFactory") { 9 | OtTracerFactory tracer_factory; 10 | std::string error_message; 11 | 12 | SECTION("Construction a tracer from invalid json fails.") { 13 | const char *configuration = R"( 14 | { 15 | 1 + 2 16 | )"; 17 | auto tracer_maybe = tracer_factory.MakeTracer(configuration, error_message); 18 | CHECK(error_message != ""); 19 | CHECK(!tracer_maybe); 20 | } 21 | 22 | SECTION("Construction a tracer from valid json, but an invalid configuration " 23 | "fails.") { 24 | const char *configuration = R"( 25 | { 26 | "service_name": "abc", 27 | "collector_port": 0 28 | })"; 29 | auto tracer_maybe = tracer_factory.MakeTracer(configuration, error_message); 30 | CHECK(error_message != ""); 31 | CHECK(!tracer_maybe); 32 | } 33 | 34 | SECTION("Constructing tracer with sample rate") { 35 | const char *configuration = R"( 36 | { 37 | "service_name": "abc", 38 | "collector_port": 80, 39 | "collector_host": "foo.bar", 40 | "sample_rate": 0.1 41 | })"; 42 | auto tracer_maybe = tracer_factory.MakeTracer(configuration, error_message); 43 | CHECK(error_message == ""); 44 | CHECK(tracer_maybe); 45 | } 46 | 47 | SECTION("Constructing a tracer from a valid configuration succeeds.") { 48 | const char *configuration = R"( 49 | { 50 | "service_name": "abc" 51 | } 52 | )"; 53 | auto tracer_maybe = tracer_factory.MakeTracer(configuration, error_message); 54 | CHECK(error_message == ""); 55 | CHECK(tracer_maybe); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /zipkin_opentracing/test/ot_tracer_test.cc: -------------------------------------------------------------------------------- 1 | #include "../src/sampling.h" 2 | #include "../src/utility.h" 3 | #include "in_memory_reporter.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define CATCH_CONFIG_MAIN 10 | #include 11 | using namespace zipkin; 12 | namespace ot = opentracing; 13 | 14 | static bool hasTag(const Span &span, ot::string_view key, ot::Value value) { 15 | auto tag_annotation = toBinaryAnnotation(key, value); 16 | return std::any_of( 17 | std::begin(span.binaryAnnotations()), std::end(span.binaryAnnotations()), 18 | [&](const BinaryAnnotation &annotation) { 19 | if (tag_annotation.key() != annotation.key() || 20 | tag_annotation.annotationType() != annotation.annotationType()) { 21 | return false; 22 | } 23 | switch (tag_annotation.annotationType()) { 24 | case BOOL: 25 | return tag_annotation.valueBool() == annotation.valueBool(); 26 | case STRING: 27 | return tag_annotation.valueString() == annotation.valueString(); 28 | case INT64: 29 | return tag_annotation.valueInt64() == annotation.valueInt64(); 30 | case DOUBLE: 31 | return tag_annotation.valueDouble() == annotation.valueDouble(); 32 | default: 33 | throw std::runtime_error("Unhandled annotation type"); 34 | } 35 | }); 36 | } 37 | 38 | static bool IsChildOf(const zipkin::Span &a, const zipkin::Span &b) { 39 | return a.isSetParentId() && a.parentId() == b.id() && 40 | a.traceId() == b.traceId(); 41 | } 42 | 43 | TEST_CASE("ot_tracer") { 44 | auto reporter = new InMemoryReporter(); 45 | ZipkinOtTracerOptions options; 46 | auto tracer = 47 | makeZipkinOtTracer(options, std::unique_ptr(reporter)); 48 | 49 | SECTION("StartSpan applies the provided tags.") { 50 | { 51 | auto span = tracer->StartSpan( 52 | "a", {ot::SetTag("abc", 123), ot::SetTag("xyz", true)}); 53 | CHECK(span); 54 | span->Finish(); 55 | } 56 | auto span = reporter->top(); 57 | CHECK(span.name() == "a"); 58 | CHECK(hasTag(span, "abc", 123)); 59 | CHECK(hasTag(span, "xyz", true)); 60 | } 61 | 62 | SECTION("Uses sampling rate to determine whether to sample a span.") { 63 | auto r = new InMemoryReporter(); 64 | 65 | ZipkinOtTracerOptions options; 66 | options.sample_rate = 0.0; 67 | auto t = makeZipkinOtTracer(options, std::unique_ptr(r)); 68 | 69 | auto span_a = t->StartSpan("a"); 70 | CHECK(span_a); 71 | span_a->Finish(); 72 | 73 | CHECK(r->spans().empty()); 74 | } 75 | 76 | SECTION("Propagates sampling decision to child span") { 77 | ZipkinOtTracerOptions no_sampling; 78 | no_sampling.sample_rate = 0.0; 79 | auto r1 = new InMemoryReporter(); 80 | auto no_sampling_tracer = 81 | makeZipkinOtTracer(no_sampling, std::unique_ptr(r1)); 82 | 83 | ZipkinOtTracerOptions always_sample; 84 | always_sample.sample_rate = 1.0; 85 | auto r2 = new InMemoryReporter(); 86 | auto sampling_tracer = 87 | makeZipkinOtTracer(always_sample, std::unique_ptr(r2)); 88 | 89 | auto span_a = no_sampling_tracer->StartSpan("a"); 90 | CHECK(span_a); 91 | span_a->Finish(); 92 | auto span_b = 93 | sampling_tracer->StartSpan("b", {ChildOf(&span_a->context())}); 94 | CHECK(span_b); 95 | span_b->Finish(); 96 | 97 | CHECK(r1->spans().empty()); 98 | CHECK(r2->spans().empty()); 99 | } 100 | 101 | SECTION("You can set a single child-of reference when starting a span.") { 102 | auto span_a = tracer->StartSpan("a"); 103 | CHECK(span_a); 104 | span_a->Finish(); 105 | auto span_b = tracer->StartSpan("b", {ChildOf(&span_a->context())}); 106 | CHECK(span_b); 107 | span_b->Finish(); 108 | auto spans = reporter->spans(); 109 | CHECK(IsChildOf(spans.at(1), spans.at(0))); 110 | } 111 | 112 | SECTION("You can set a single follows-from reference when starting a span.") { 113 | auto span_a = tracer->StartSpan("a"); 114 | CHECK(span_a); 115 | span_a->Finish(); 116 | auto span_b = tracer->StartSpan("b", {FollowsFrom(&span_a->context())}); 117 | CHECK(span_b); 118 | span_b->Finish(); 119 | auto spans = reporter->spans(); 120 | // FollowsFrom is treated the same as ChildOf. 121 | CHECK(IsChildOf(spans.at(1), spans.at(0))); 122 | } 123 | 124 | SECTION("Baggage from the span references are copied over to a new span " 125 | "context") { 126 | auto span_a = tracer->StartSpan("a"); 127 | CHECK(span_a); 128 | span_a->SetBaggageItem("a", "1"); 129 | auto span_b = tracer->StartSpan("b", {ot::ChildOf(&span_a->context())}); 130 | CHECK(span_b); 131 | CHECK(span_b->BaggageItem("a") == "1"); 132 | } 133 | 134 | SECTION("References to non-Zipkin spans and null pointers are ignored.") { 135 | auto noop_tracer = ot::MakeNoopTracer(); 136 | auto noop_span = noop_tracer->StartSpan("noop"); 137 | CHECK(noop_span); 138 | ot::StartSpanOptions options; 139 | options.references.push_back(std::make_pair( 140 | ot::SpanReferenceType::ChildOfRef, &noop_span->context())); 141 | options.references.push_back( 142 | std::make_pair(ot::SpanReferenceType::ChildOfRef, nullptr)); 143 | auto span = tracer->StartSpanWithOptions("a", options); 144 | CHECK(span); 145 | span->Finish(); 146 | CHECK(!reporter->top().isSetParentId()); 147 | } 148 | 149 | SECTION("Calling Finish a second time does nothing.") { 150 | auto span = tracer->StartSpan("a"); 151 | CHECK(span); 152 | span->Finish(); 153 | CHECK(reporter->size() == 1); 154 | span->Finish(); 155 | CHECK(reporter->size() == 1); 156 | } 157 | 158 | SECTION("The operation name can be changed after the span is started.") { 159 | auto span = tracer->StartSpan("a"); 160 | CHECK(span); 161 | span->SetOperationName("b"); 162 | span->Finish(); 163 | CHECK(reporter->top().name() == "b"); 164 | } 165 | 166 | SECTION("Tags can be specified after a span is started.") { 167 | auto span = tracer->StartSpan("a"); 168 | CHECK(span); 169 | span->SetTag("abc", 123); 170 | span->Finish(); 171 | CHECK(hasTag(reporter->top(), "abc", 123)); 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /zipkin_opentracing/tracer_configuration.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema#", 3 | "title": "TracerConfiguration", 4 | "description": "Configuration for a Zipkin tracer", 5 | "type": "object", 6 | "required": ["service_name"], 7 | "properties": { 8 | "service_name": { 9 | "type": "string", 10 | "description": "Specifies default Zipkin endpoint annotation.\nIdentifies the application's service" 11 | }, 12 | "service_address": { 13 | "type": "string", 14 | "description": "IP address to use with the default Zipkin endpoint annotation" 15 | }, 16 | "collector_host": { 17 | "type": "string", 18 | "description": "Host to use when connecting to Zipkin's collector" 19 | }, 20 | "collector_port": { 21 | "type": "integer", 22 | "minimum": 1, 23 | "maximum": 65535, 24 | "description": "Port to use when connecting to Zipkin's collector" 25 | }, 26 | "reporting_period": { 27 | "type": "integer", 28 | "minimum": 1, 29 | "description": 30 | "The time in microseconds between sending successive reports to the collector" 31 | }, 32 | "max_buffered_spans": { 33 | "type": "integer", 34 | "minimum": 1, 35 | "description": 36 | "The maximum number of spans to buffer before sending them to the collector" 37 | }, 38 | "sample_rate": { 39 | "type": "number", 40 | "minimum": 0.0, 41 | "maximum": 1.0, 42 | "description": "The probability of sampling a span" 43 | } 44 | } 45 | } 46 | 47 | --------------------------------------------------------------------------------