summaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/opentracing/dynamic_load.h151
-rw-r--r--include/opentracing/ext/tags.h122
-rw-r--r--include/opentracing/noop.h28
-rw-r--r--include/opentracing/propagation.h205
-rw-r--r--include/opentracing/span.h228
-rw-r--r--include/opentracing/string_view.h144
-rw-r--r--include/opentracing/symbols.h34
-rw-r--r--include/opentracing/tracer.h277
-rw-r--r--include/opentracing/tracer_factory.h56
-rw-r--r--include/opentracing/util.h84
-rw-r--r--include/opentracing/value.h68
11 files changed, 1397 insertions, 0 deletions
diff --git a/include/opentracing/dynamic_load.h b/include/opentracing/dynamic_load.h
new file mode 100644
index 0000000..f8f9837
--- /dev/null
+++ b/include/opentracing/dynamic_load.h
@@ -0,0 +1,151 @@
+#ifndef OPENTRACING_DYNAMIC_LOAD_H
+#define OPENTRACING_DYNAMIC_LOAD_H
+
+#include <opentracing/config.h>
+#include <opentracing/symbols.h>
+#include <opentracing/tracer.h>
+#include <opentracing/tracer_factory.h>
+#include <opentracing/version.h>
+#include <system_error>
+
+// OpenTracingMakeTracerFactory provides a common hook that can be used to
+// create an TracerFactory from a dynamically loaded library. Users should
+// prefer to use the function DynamicallyLoadTracingLibrary over calling it
+// directly.
+//
+// It takes the parameter `opentracing_version` and `opentracing_abi_version`
+// representing the version of opentracing used by the caller. Upon success it
+// returns the code `0` and sets `tracer_factory` to point to an instance of
+// TracerFactory.
+//
+// On failure, it returns a non-zero error code and sets `error_category` to
+// point to an std::error_category for the returned error code.
+//
+// Example usage,
+//
+// const std::error_category* error_category = nullptr;
+// std::string error_message;
+// opentracing::TracerFactory* tracer_factory = nullptr;
+// int rcode = (*OpenTracingMakeTracerFactory)(
+// OPENTRACING_VERSION,
+// OPENTRACING_ABI_VERSION,
+// &static_cast<const void*>(error_category),
+// static_cast<void*>(&error_message),
+// &static_cast<void*>(tracer_factory));
+// if (rcode == 0) {
+// // success
+// assert(tracer_factory != nullptr);
+// } else {
+// // failure
+// assert(error_category != nullptr);
+// std::error_code error{rcode, *error_category};
+// }
+using OpenTracingMakeTracerFactoryType = int(
+ const char* opentracing_version, const char* opentracing_abi_version,
+ const void** error_category, void* error_message, void** tracer_factory);
+
+#ifdef WIN32
+
+#define OPENTRACING_DECLARE_IMPL_FACTORY(X) \
+ extern "C" { \
+ \
+ extern __declspec(dllexport) \
+ OpenTracingMakeTracerFactoryType* const OpenTracingMakeTracerFactory; \
+ \
+ __declspec(selectany) OpenTracingMakeTracerFactoryType* const \
+ OpenTracingMakeTracerFactory = X; \
+ } // extern "C"
+
+#else
+
+#define OPENTRACING_DECLARE_IMPL_FACTORY(X) \
+ extern "C" { \
+ \
+ __attribute((weak)) extern OpenTracingMakeTracerFactoryType* const \
+ OpenTracingMakeTracerFactory; \
+ \
+ OpenTracingMakeTracerFactoryType* const OpenTracingMakeTracerFactory = X; \
+ } // extern "C"
+
+#endif
+
+namespace opentracing {
+BEGIN_OPENTRACING_ABI_NAMESPACE
+// Returns the std::error_category class used for opentracing dynamic loading
+// errors.
+//
+// See
+// http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-1.html
+// https://ned14.github.io/boost.outcome/md_doc_md_03-tutorial_b.html
+OPENTRACING_API const std::error_category& dynamic_load_error_category();
+
+// `dynamic_load_failure_error` occurs when dynamically loading a tracer library
+// fails. Possible reasons could be the library doesn't exist or it is missing
+// the required symbols.
+const std::error_code dynamic_load_failure_error(1,
+ dynamic_load_error_category());
+
+// `dynamic_load_not_supported_error` means dynamic loading of tracing libraries
+// is not supported for the platform used.
+const std::error_code dynamic_load_not_supported_error(
+ 2, dynamic_load_error_category());
+
+// `incompatible_library_versions_error` occurs if the tracing library
+// dynamically loaded uses an incompatible version of opentracing.
+const std::error_code incompatible_library_versions_error(
+ 3, dynamic_load_error_category());
+
+class DynamicLibraryHandle {
+ public:
+ virtual ~DynamicLibraryHandle() = default;
+};
+
+// Provides a handle to a dynamically loaded tracing library that can be used
+// to create tracers.
+//
+// Note: The handle must not be destructed while any associated tracers are
+// still in use.
+//
+// See TracerFactory
+class DynamicTracingLibraryHandle {
+ public:
+ DynamicTracingLibraryHandle() = default;
+
+ DynamicTracingLibraryHandle(
+ std::unique_ptr<const TracerFactory>&& tracer_factory,
+ std::unique_ptr<DynamicLibraryHandle>&& dynamic_library_handle) noexcept;
+
+ const TracerFactory& tracer_factory() const noexcept {
+ return *tracer_factory_;
+ }
+
+ private:
+ std::unique_ptr<DynamicLibraryHandle> dynamic_library_handle_;
+ std::unique_ptr<const TracerFactory> tracer_factory_;
+};
+
+// Dynamically loads a tracing library and returns a handle that can be used
+// to create tracers.
+//
+// Example:
+// std::string error_message;
+// auto handle_maybe = DynamicallyLoadTracingLibrary(
+// "libtracing_vendor.so",
+// error_message);
+// if (handle_maybe) {
+// // success
+// auto& tracer_factory = handle_maybe->tracer_factory();
+// } else {
+// // failure
+// std::error_code error = handle_maybe.error();
+// // `error_message` may also contain a more descriptive message
+// }
+//
+// See DynamicTracingLibraryHandle, TracerFactory
+OPENTRACING_API expected<DynamicTracingLibraryHandle>
+DynamicallyLoadTracingLibrary(const char* shared_library,
+ std::string& error_message) noexcept;
+END_OPENTRACING_ABI_NAMESPACE
+} // namespace opentracing
+
+#endif // OPENTRACING_DYNAMIC_LOAD_H
diff --git a/include/opentracing/ext/tags.h b/include/opentracing/ext/tags.h
new file mode 100644
index 0000000..746cd37
--- /dev/null
+++ b/include/opentracing/ext/tags.h
@@ -0,0 +1,122 @@
+#ifndef OPENTRACING_EXT_TAGS_H
+#define OPENTRACING_EXT_TAGS_H
+
+#include <opentracing/string_view.h>
+#include <opentracing/symbols.h>
+#include <opentracing/version.h>
+
+namespace opentracing {
+BEGIN_OPENTRACING_ABI_NAMESPACE
+namespace ext {
+// The following tags are described in greater detail at the following url:
+// https://github.com/opentracing/specification/blob/master/semantic_conventions.md
+//
+// Here we define standard names for tags that can be added to spans by the
+// instrumentation code. The actual tracing systems are not required to
+// retain these as tags in the stored spans if they have other means of
+// representing the same data. For example, the SPAN_KIND='server' can be
+// inferred from a Zipkin span by the presence of ss/sr annotations.
+
+// ---------------------------------------------------------------------------
+// span_kind hints at relationship between spans, e.g. client/server
+// ---------------------------------------------------------------------------
+OPENTRACING_API extern const opentracing::string_view span_kind;
+
+// Marks a span representing the client-side of an RPC or other remote call
+OPENTRACING_API extern const opentracing::string_view span_kind_rpc_client;
+
+// Marks a span representing the server-side of an RPC or other remote call
+OPENTRACING_API extern const opentracing::string_view span_kind_rpc_server;
+
+// ---------------------------------------------------------------------------
+// error indicates whether a Span ended in an error state.
+// ---------------------------------------------------------------------------
+OPENTRACING_API extern const opentracing::string_view error;
+
+// ---------------------------------------------------------------------------
+// component (string) ia s low-cardinality identifier of the module, library,
+// or package that is generating a span.
+// ---------------------------------------------------------------------------
+OPENTRACING_API extern const opentracing::string_view component;
+
+// ---------------------------------------------------------------------------
+// sampling_priority (uint16) determines the priority of sampling this Span.
+// ---------------------------------------------------------------------------
+OPENTRACING_API extern const opentracing::string_view sampling_priority;
+
+// ---------------------------------------------------------------------------
+// peer_* tags can be emitted by either client-side of server-side to describe
+// the other side/service in a peer-to-peer communications, like an RPC call.
+// ---------------------------------------------------------------------------
+// peer_service (string) records the service name of the peer
+OPENTRACING_API extern const opentracing::string_view peer_service;
+
+// peer_hostname (string) records the host name of the peer
+OPENTRACING_API extern const opentracing::string_view peer_hostname;
+
+// peer_address (string) suitable for use in a networking client library.
+// This may be a "ip:port", a bare "hostname", a FQDN, or even a
+// JDBC substring like "mysql://prod-db:3306"
+OPENTRACING_API extern const opentracing::string_view peer_address;
+
+// peer_host_ipv4 (uint32) records IP v4 host address of the peer
+OPENTRACING_API extern const opentracing::string_view peer_host_ipv4;
+
+// peer_host_ipv6 (string) records IP v6 host address of the peer
+OPENTRACING_API extern const opentracing::string_view peer_host_ipv6;
+
+// peer_port (uint16) records port number of the peer
+OPENTRACING_API extern const opentracing::string_view peer_port;
+
+// ---------------------------------------------------------------------------
+// HTTP tags
+// ---------------------------------------------------------------------------
+
+// http_url (string) should be the URL of the request being handled in this
+// segment of the trace, in standard URI format. The protocol is optional.
+OPENTRACING_API extern const opentracing::string_view http_url;
+
+// http_method (string) is the HTTP method of the request.
+// Both upper/lower case values are allowed.
+OPENTRACING_API extern const opentracing::string_view http_method;
+
+// http_status_code (int) is the numeric HTTP status code (200, 404, etc)
+// of the HTTP response.
+OPENTRACING_API extern const opentracing::string_view http_status_code;
+
+// ---------------------------------------------------------------------------
+// DATABASE tags
+// ---------------------------------------------------------------------------
+
+// database_instance (string) The database instance name. E.g., In java, if
+// the jdbc.url="jdbc:mysql://127.0.0.1:3306/customers", the instance
+// name is "customers"
+OPENTRACING_API extern const opentracing::string_view database_instance;
+
+// database_statement (string) A database statement for the given database
+// type. E.g., for db.type="SQL", "SELECT * FROM user_table";
+// for db.type="redis", "SET mykey 'WuValue'".
+OPENTRACING_API extern const opentracing::string_view database_statement;
+
+// database_type (string) For any SQL database, "sql". For others,
+// the lower-case database category, e.g. "cassandra", "hbase", or "redis".
+OPENTRACING_API extern const opentracing::string_view database_type;
+
+// database_user (string) Username for accessing database. E.g.,
+// "readonly_user" or "reporting_user"
+OPENTRACING_API extern const opentracing::string_view database_user;
+
+// ---------------------------------------------------------------------------
+// message_bus tags
+// ---------------------------------------------------------------------------
+
+// message_bus_destination (string) An address at which messages can be
+// exchanged. E.g. A Kafka record has an associated "topic name" that can
+// be extracted by the instrumented producer or consumer and stored
+// using this tag.
+OPENTRACING_API extern const opentracing::string_view message_bus_destination;
+} // namespace ext
+END_OPENTRACING_ABI_NAMESPACE
+} // namespace opentracing
+
+#endif // OPENTRACING_EXT_TAGS_H
diff --git a/include/opentracing/noop.h b/include/opentracing/noop.h
new file mode 100644
index 0000000..5313489
--- /dev/null
+++ b/include/opentracing/noop.h
@@ -0,0 +1,28 @@
+#ifndef OPENTRACING_NOOP_H
+#define OPENTRACING_NOOP_H
+
+#include <opentracing/symbols.h>
+#include <opentracing/tracer.h>
+#include <opentracing/version.h>
+#include <memory>
+
+namespace opentracing {
+BEGIN_OPENTRACING_ABI_NAMESPACE
+// A NoopTracer is a trivial, minimum overhead implementation of Tracer
+// for which all operations are no-ops.
+//
+// The primary use of this implementation is in libraries, such as RPC
+// frameworks, that make tracing an optional feature controlled by the
+// end user. A no-op implementation allows said libraries to use it
+// as the default Tracer and to write instrumentation that does
+// not need to keep checking if the tracer instance is nil.
+//
+// For the same reason, the NoopTracer is the default "global" tracer
+// (see Tracer::Global and Tracer::InitGlobal functions).
+//
+// WARNING: NoopTracer does not support baggage propagation.
+OPENTRACING_API std::shared_ptr<Tracer> MakeNoopTracer() noexcept;
+END_OPENTRACING_ABI_NAMESPACE
+} // namespace opentracing
+
+#endif // OPENTRACING_NOOP_H
diff --git a/include/opentracing/propagation.h b/include/opentracing/propagation.h
new file mode 100644
index 0000000..c4edc6a
--- /dev/null
+++ b/include/opentracing/propagation.h
@@ -0,0 +1,205 @@
+#ifndef OPENTRACING_PROPAGATION_H
+#define OPENTRACING_PROPAGATION_H
+
+#include <opentracing/string_view.h>
+#include <opentracing/symbols.h>
+#include <opentracing/util.h>
+#include <opentracing/version.h>
+#include <functional>
+#include <memory>
+#include <string>
+#include <system_error>
+
+namespace opentracing {
+BEGIN_OPENTRACING_ABI_NAMESPACE
+class Tracer;
+class SpanContext;
+
+enum class SpanReferenceType {
+ // ChildOfRef refers to a parent Span that caused *and* somehow depends
+ // upon the new child Span. Often (but not always), the parent Span cannot
+ // finish until the child Span does.
+ //
+ // An timing diagram for a ChildOfRef that's blocked on the new Span:
+ //
+ // [-Parent Span---------]
+ // [-Child Span----]
+ //
+ // See http://opentracing.io/spec/
+ //
+ // See opentracing.ChildOf()
+ ChildOfRef = 1,
+
+ // FollowsFromRef refers to a parent Span that does not depend in any way
+ // on the result of the new child Span. For instance, one might use
+ // FollowsFromRefs to describe pipeline stages separated by queues,
+ // or a fire-and-forget cache insert at the tail end of a web request.
+ //
+ // A FollowsFromRef Span is part of the same logical trace as the new Span:
+ // i.e., the new Span is somehow caused by the work of its FollowsFromRef.
+ //
+ // All of the following could be valid timing diagrams for children that
+ // "FollowFrom" a parent.
+ //
+ // [-Parent Span-] [-Child Span-]
+ //
+ //
+ // [-Parent Span--]
+ // [-Child Span-]
+ //
+ //
+ // [-Parent Span-]
+ // [-Child Span-]
+ //
+ // See http://opentracing.io/spec/
+ //
+ // See opentracing.FollowsFrom()
+ FollowsFromRef = 2
+};
+
+// Returns the std::error_category class used for opentracing propagation
+// errors.
+//
+// See
+// http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-1.html
+// https://ned14.github.io/boost.outcome/md_doc_md_03-tutorial_b.html
+OPENTRACING_API const std::error_category& propagation_error_category();
+
+// `invalid_span_context_error` occurs when Tracer::Inject() is asked to operate
+// on a SpanContext which it is not prepared to handle (for example, since it
+// was created by a different tracer implementation).
+const std::error_code invalid_span_context_error(1,
+ propagation_error_category());
+
+// `invalid_carrier_error` occurs when Tracer::Inject() or Tracer::Extract()
+// implementations expect a different type of `carrier` than they are given.
+const std::error_code invalid_carrier_error(2, propagation_error_category());
+
+// `span_context_corrupted_error` occurs when the `carrier` passed to
+// Tracer::Extract() is of the expected type but is corrupted.
+const std::error_code span_context_corrupted_error(
+ 3, propagation_error_category());
+
+// `key_not_found_error` occurs when TextMapReader::LookupKey fails to find
+// an entry for the provided key.
+const std::error_code key_not_found_error(4, propagation_error_category());
+
+// `lookup_key_not_supported_error` occurs when TextMapReader::LookupKey is
+// not supported for the provided key.
+const std::error_code lookup_key_not_supported_error(
+ 5, propagation_error_category());
+
+// TextMapReader is the Extract() carrier for the TextMap builtin format. With
+// it, the caller can decode a SpanContext from entries in a propagated map of
+// Unicode strings.
+//
+// See the HTTPHeaders examples.
+class TextMapReader {
+ public:
+ virtual ~TextMapReader() = default;
+
+ // LookupKey returns the value for the specified `key` if available. If no
+ // such key is present, it returns `key_not_found_error`.
+ //
+ // TextMapReaders are not required to implement this method. If not supported,
+ // the function returns `lookup_key_not_supported_error`.
+ //
+ // Tracers may use this as an alternative to `ForeachKey` as a faster way to
+ // extract span context.
+ virtual expected<string_view> LookupKey(string_view /*key*/) const {
+ return make_unexpected(lookup_key_not_supported_error);
+ }
+
+ // ForeachKey returns TextMap contents via repeated calls to the `f`
+ // function. If any call to `f` returns an error, ForeachKey terminates and
+ // returns that error.
+ //
+ // NOTE: The backing store for the TextMapReader may contain data unrelated
+ // to SpanContext. As such, Inject() and Extract() implementations that
+ // call the TextMapWriter and TextMapReader interfaces must agree on a
+ // prefix or other convention to distinguish their own key:value pairs.
+ //
+ // The "foreach" callback pattern reduces unnecessary copying in some cases
+ // and also allows implementations to hold locks while the map is read.
+ virtual expected<void> ForeachKey(
+ std::function<expected<void>(string_view key, string_view value)> f)
+ const = 0;
+};
+
+// TextMapWriter is the Inject() carrier for the TextMap builtin format. With
+// it, the caller can encode a SpanContext for propagation as entries in a map
+// of unicode strings.
+//
+// See the HTTPHeaders examples.
+class TextMapWriter {
+ public:
+ virtual ~TextMapWriter() = default;
+
+ // Set a key:value pair to the carrier. Multiple calls to Set() for the
+ // same key leads to undefined behavior.
+ //
+ // NOTE: The backing store for the TextMapWriter may contain data unrelated
+ // to SpanContext. As such, Inject() and Extract() implementations that
+ // call the TextMapWriter and TextMapReader interfaces must agree on a
+ // prefix or other convention to distinguish their own key:value pairs.
+ virtual expected<void> Set(string_view key, string_view value) const = 0;
+};
+
+// HTTPHeadersReader is the Extract() carrier for the HttpHeaders builtin
+// format. With it, the caller can decode a SpanContext from entries in HTTP
+// request headers.
+//
+// For example, Extract():
+//
+// const Tracer& tracer = /* some tracer */
+// const HTTPHeadersReader& carrier_reader = /* some carrier */
+// auto span_context_maybe = tracer.Extract(carrier_reader);
+// if (!span_context_maybe) {
+// throw std::runtime_error(span_context_maybe.error().message());
+// }
+// auto span = tracer.StartSpan("op",
+// { ChildOf(span_context_maybe->get()) });
+class HTTPHeadersReader : public TextMapReader {};
+
+// HTTPHeadersWriter is the Inject() carrier for the TextMap builtin format.
+// With it, the caller can encode a SpanContext for propagation as entries in
+// http request headers
+//
+// For example, Inject():
+//
+// const HTTPHeadersWriter& carrier_writer = /* some carrier */
+// auto was_successful = span.tracer().Inject(span,
+// carrier_writer);
+// if (!was_successful) {
+// throw std::runtime_error(was_successful.error().message());
+// }
+class HTTPHeadersWriter : public TextMapWriter {};
+
+// CustomCarrierReader is the Extract() carrier for a custom format. With it,
+// the caller can decode a SpanContext from entries in a custom protocol.
+class CustomCarrierReader {
+ public:
+ virtual ~CustomCarrierReader() = default;
+
+ // Extract is expected to specialize on the tracer implementation so as to
+ // most efficiently decode its context.
+ virtual expected<std::unique_ptr<SpanContext>> Extract(
+ const Tracer& tracer) const = 0;
+};
+
+// CustomCarrierWriter is the Inject() carrier for a custom format. With it,
+// the caller can encode a SpanContext for propagation as entries in a custom
+// protocol.
+class CustomCarrierWriter {
+ public:
+ virtual ~CustomCarrierWriter() = default;
+
+ // Inject is expected to specialize on the tracer implementation so as to most
+ // efficiently encode its context.
+ virtual expected<void> Inject(const Tracer& tracer,
+ const SpanContext& sc) const = 0;
+};
+END_OPENTRACING_ABI_NAMESPACE
+} // namespace opentracing
+
+#endif // OPENTRACING_PROPAGATION_H
diff --git a/include/opentracing/span.h b/include/opentracing/span.h
new file mode 100644
index 0000000..a48b33c
--- /dev/null
+++ b/include/opentracing/span.h
@@ -0,0 +1,228 @@
+#ifndef OPENTRACING_SPAN_H
+#define OPENTRACING_SPAN_H
+
+#include <opentracing/string_view.h>
+#include <opentracing/util.h>
+#include <opentracing/value.h>
+#include <opentracing/version.h>
+#include <chrono>
+#include <functional>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace opentracing {
+BEGIN_OPENTRACING_ABI_NAMESPACE
+class Tracer;
+
+// SpanContext represents Span state that must propagate to descendant Spans and
+// across process boundaries (e.g., a <trace_id, span_id, sampled> tuple).
+class SpanContext {
+ public:
+ virtual ~SpanContext() = default;
+
+ // ForeachBaggageItem calls a function for each baggage item in the
+ // context. If the function returns false, it will not be called
+ // again and ForeachBaggageItem will return.
+ virtual void ForeachBaggageItem(
+ std::function<bool(const std::string& key, const std::string& value)> f)
+ const = 0;
+
+ // Clone creates a copy of SpanContext.
+ //
+ // Returns nullptr on failure.
+ virtual std::unique_ptr<SpanContext> Clone() const noexcept = 0;
+
+ // Return the ID of the trace.
+ //
+ // Should be globally unique. Every span in a trace shares this ID.
+ //
+ // An empty string will be returned if the tracer does not support this
+ // functionality or an error occurs (this is the case for no-op traces, for
+ // example).
+ virtual std::string ToTraceID() const noexcept { return {}; }
+
+ // Return the ID of the associated Span.
+ //
+ // Should be unique within a trace. Each span within a trace contains a
+ // different ID.
+ //
+ // An empty string will be returned if the tracer does not support this
+ // functionality or an error occurs (this is the case for no-op traces, for
+ // example).
+ virtual std::string ToSpanID() const noexcept { return {}; }
+};
+
+struct LogRecord {
+ using Field = std::pair<std::string, Value>;
+
+ SystemTime timestamp;
+ std::vector<Field> fields;
+};
+
+inline bool operator==(const LogRecord& lhs, const LogRecord& rhs) {
+ return lhs.timestamp == rhs.timestamp && lhs.fields == rhs.fields;
+}
+
+inline bool operator!=(const LogRecord& lhs, const LogRecord& rhs) {
+ return !(lhs == rhs);
+}
+
+// FinishOptions allows Span.Finish callers to override the finish
+// timestamp.
+struct FinishSpanOptions {
+ SteadyTime finish_steady_timestamp;
+
+ // log_records allows the caller to specify the contents of many Log() calls
+ // with a single vector. May be empty.
+ //
+ // None of the LogRecord.timestamp values may be SystemTime() (i.e., they must
+ // be set explicitly). Also, they must be >= the Span's start system timestamp
+ // and <= the finish_steady_timestamp converted to system timestamp
+ // (or SystemTime::now() if finish_steady_timestamp is default-constructed).
+ // Otherwise the behavior of FinishWithOptions() is unspecified.
+ std::vector<LogRecord> log_records;
+};
+
+// FinishSpanOption instances (zero or more) may be passed to Span.Finish.
+class FinishSpanOption {
+ public:
+ FinishSpanOption(const FinishSpanOption&) = delete;
+
+ virtual ~FinishSpanOption() = default;
+
+ virtual void Apply(FinishSpanOptions& options) const noexcept = 0;
+
+ protected:
+ FinishSpanOption() = default;
+};
+
+// Span represents an active, un-finished span in the OpenTracing system.
+//
+// Spans are created by the Tracer interface.
+class Span {
+ public:
+ // If Finish has not already been called for the Span, it's destructor must
+ // do so.
+ virtual ~Span() = default;
+
+ // Sets the end timestamp and finalizes Span state.
+ //
+ // If Finish is called a second time, it is guaranteed to do nothing.
+ void Finish(std::initializer_list<option_wrapper<FinishSpanOption>>
+ option_list = {}) noexcept {
+ FinishSpanOptions options;
+ options.finish_steady_timestamp = SteadyClock::now();
+ for (const auto& option : option_list) option.get().Apply(options);
+ FinishWithOptions(options);
+ }
+
+ virtual void FinishWithOptions(
+ const FinishSpanOptions& finish_span_options) noexcept = 0;
+
+ // Sets or changes the operation name.
+ //
+ // If SetOperationName is called after Finish it leaves the Span in a valid
+ // state, but its behavior is unspecified.
+ virtual void SetOperationName(string_view name) noexcept = 0;
+
+ // Adds a tag to the span.
+ //
+ // If there is a pre-existing tag set for `key`, it is overwritten.
+ //
+ // Tag values can be numeric types, strings, or bools. The behavior of
+ // other tag value types is undefined at the OpenTracing level. If a
+ // tracing system does not know how to handle a particular value type, it
+ // may ignore the tag, but shall not panic.
+ //
+ // If SetTag is called after Finish it leaves the Span in a valid state, but
+ // its behavior is unspecified.
+ virtual void SetTag(string_view key, const Value& value) noexcept = 0;
+
+ // SetBaggageItem sets a key:value pair on this Span and its SpanContext
+ // that also propagates to descendants of this Span.
+ //
+ // SetBaggageItem() enables powerful functionality given a full-stack
+ // opentracing integration (e.g., arbitrary application data from a mobile
+ // app can make it, transparently, all the way into the depths of a storage
+ // system), and with it some powerful costs: use this feature with care.
+ //
+ // IMPORTANT NOTE #1: SetBaggageItem() will only propagate baggage items to
+ // *future* causal descendants of the associated Span.
+ //
+ // IMPORTANT NOTE #2: Use this thoughtfully and with care. Every key and
+ // value is copied into every local *and remote* child of the associated
+ // Span, and that can add up to a lot of network and cpu overhead.
+ //
+ // If SetBaggageItem is called after Finish it leaves the Span in a valid
+ // state, but its behavior is unspecified.
+ virtual void SetBaggageItem(string_view restricted_key,
+ string_view value) noexcept = 0;
+
+ // Gets the value for a baggage item given its key. Returns the empty string
+ // if the value isn't found in this Span.
+ virtual std::string BaggageItem(string_view restricted_key) const
+ noexcept = 0;
+
+ // Log is an efficient and type-checked way to record key:value logging data
+ // about a Span. Here's an example:
+ //
+ // span.Log({
+ // {"event", "soft error"},
+ // {"type", "cache timeout"},
+ // {"waited.millis", 1500}});
+ virtual void Log(
+ std::initializer_list<std::pair<string_view, Value>> fields) noexcept = 0;
+
+ virtual void Log(
+ SystemTime timestamp,
+ std::initializer_list<std::pair<string_view, Value>> fields) noexcept = 0;
+
+ virtual void Log(
+ SystemTime timestamp,
+ const std::vector<std::pair<string_view, Value>>& fields) noexcept = 0;
+
+ // context() yields the SpanContext for this Span. Note that the return
+ // value of context() is still valid after a call to Span.Finish(), as is
+ // a call to Span.context() after a call to Span.Finish().
+ virtual const SpanContext& context() const noexcept = 0;
+
+ // Provides access to the Tracer that created this Span.
+ virtual const Tracer& tracer() const noexcept = 0;
+};
+
+// FinishTimestamp is a FinishSpanOption that sets an explicit finish timestamp
+// for a Span.
+class FinishTimestamp : public FinishSpanOption {
+ public:
+ explicit FinishTimestamp(SteadyTime steady_when) noexcept
+ : steady_when_(steady_when) {}
+
+ // Construct a timestamp using a duration from the epoch of std::time_t.
+ // From the documentation on std::time_t's epoch:
+ // Although not defined, this is almost always an integral value holding
+ // the number of seconds (not counting leap seconds) since 00:00, Jan 1
+ // 1970 UTC, corresponding to POSIX time
+ // See http://en.cppreference.com/w/cpp/chrono/c/time_t
+ template <class Rep, class Period>
+ explicit FinishTimestamp(
+ const std::chrono::duration<Rep, Period>& time_since_epoch) noexcept
+ : steady_when_(convert_time_point<SteadyClock>(
+ SystemClock::from_time_t(std::time_t(0)) +
+ std::chrono::duration_cast<SystemClock::duration>(
+ time_since_epoch))) {}
+
+ FinishTimestamp(const FinishTimestamp& other) noexcept
+ : FinishSpanOption(), steady_when_(other.steady_when_) {}
+
+ void Apply(FinishSpanOptions& options) const noexcept override {
+ options.finish_steady_timestamp = steady_when_;
+ }
+
+ private:
+ SteadyTime steady_when_;
+};
+END_OPENTRACING_ABI_NAMESPACE
+} // namespace opentracing
+
+#endif // OPENTRACING_SPAN_H
diff --git a/include/opentracing/string_view.h b/include/opentracing/string_view.h
new file mode 100644
index 0000000..a30eb7f
--- /dev/null
+++ b/include/opentracing/string_view.h
@@ -0,0 +1,144 @@
+#ifndef OPENTRACING_STRING_VIEW_H
+#define OPENTRACING_STRING_VIEW_H
+
+#include <opentracing/version.h>
+#include <algorithm>
+#include <cstring>
+#include <ostream>
+#include <string>
+
+// ===========
+// string_view.h
+// ===========
+// class string_view - Constant reference to an external string
+//
+// -----------------
+// String References
+// -----------------
+// This string references is a simplified version of the boost::string_ref.
+// Its purpose is to avoid a number of efficiency problems that appear
+// commonly when interacting with 'std::string' and c-strings.
+//
+// See the boost documentation for more background:
+// http://www.boost.org/doc/libs/master/libs/utility/doc/html/string_ref.html
+//
+// -----
+// Note:
+// -----
+// Although we have the ability to use wide string refs, there are side
+// effects in exposing an OpenTracing interface that works with narrow and wide
+// strings at the same time. Storage on the implementation will have a 'native'
+// format.
+//
+// Exposing references to that format avoid copies means clients would be
+// dependent on that format. If they're dependent on that detail and then switch
+// out the implementation to a different format, there would be lots of code
+// that breaks if it was expecting wstring and starts receiving string all of a
+// sudden. That design issue still needs to be addressed.
+
+namespace opentracing {
+BEGIN_OPENTRACING_ABI_NAMESPACE
+// ===============
+// class string_view
+// ===============
+// Represent a constant reference to an external character array. The external
+// array need not be null-terminated, if explicitly created with a known length.
+//
+// This class does not own the data. It is expected to be used in situations
+// where the character data resides in some other buffer, whose lifetime extends
+// past that of the string_view. For this reason, it is not in general safe to
+// store a string_view.
+
+class string_view {
+ public:
+ // Construct an empty string_view
+ string_view() noexcept : data_(nullptr), length_(0) {}
+
+ // create string reference from const character pointer
+ string_view(const char* str) noexcept
+ : data_(str), length_(std::strlen(str)) {}
+
+ // Create constant string reference from pointer and length
+ string_view(const std::basic_string<char>& str) noexcept
+ : data_(str.c_str()), length_(str.length()) {}
+
+ // Create constant string reference from pointer and length
+ string_view(const char* str, size_t len) noexcept
+ : data_(str), length_(len) {}
+
+ // Implicit conversion to std::string
+ operator std::string() const { return {data_, length_}; }
+
+ // Return address of the referenced string
+ const char* data() const noexcept { return data_; }
+
+ // Returns true if `length_` == 0
+ bool empty() const noexcept { return length_ == 0; }
+
+ // Return the length of the referenced string
+ size_t length() const noexcept { return length_; }
+ size_t size() const noexcept { return length_; }
+
+ // Returns a RandomAccessIterator to the first element.
+ const char* begin() const noexcept { return data(); }
+
+ // Returns a RandomAccessIterator for the last element.
+ const char* end() const noexcept { return data() + length(); }
+
+ // Returns the character in the i-th position.
+ const char& operator[](std::size_t i) { return *(data() + i); }
+
+ private:
+ const char* data_; // Pointer to external storage
+ size_t length_; // Length of data pointed to by 'data_'
+};
+
+inline bool operator==(string_view lhs, string_view rhs) noexcept {
+ return lhs.length() == rhs.length() &&
+ std::equal(lhs.data(), lhs.data() + lhs.length(), rhs.data());
+}
+
+inline bool operator==(string_view lhs, const std::string& rhs) noexcept {
+ return lhs == string_view(rhs);
+}
+
+inline bool operator==(const std::string& lhs, string_view rhs) noexcept {
+ return string_view(lhs) == rhs;
+}
+
+inline bool operator==(string_view lhs, const char* rhs) noexcept {
+ return lhs == string_view(rhs);
+}
+
+inline bool operator==(const char* lhs, string_view rhs) noexcept {
+ return string_view(lhs) == rhs;
+}
+
+inline bool operator!=(string_view lhs, string_view rhs) noexcept {
+ return !(lhs == rhs);
+}
+
+inline bool operator!=(string_view lhs, const std::string& rhs) noexcept {
+ return !(lhs == rhs);
+}
+
+inline bool operator!=(const std::string& lhs, string_view rhs) noexcept {
+ return !(lhs == rhs);
+}
+
+inline bool operator!=(string_view lhs, const char* rhs) noexcept {
+ return !(lhs == rhs);
+}
+
+inline bool operator!=(const char* lhs, string_view rhs) noexcept {
+ return !(lhs == rhs);
+}
+
+inline std::ostream& operator<<(std::ostream& os,
+ const opentracing::string_view& ref) {
+ return os.write(ref.data(), static_cast<std::streamsize>(ref.length()));
+}
+END_OPENTRACING_ABI_NAMESPACE
+} // namespace opentracing
+
+#endif // OPENTRACING_STRING_VIEW_H
diff --git a/include/opentracing/symbols.h b/include/opentracing/symbols.h
new file mode 100644
index 0000000..b359ced
--- /dev/null
+++ b/include/opentracing/symbols.h
@@ -0,0 +1,34 @@
+#ifndef OPENTRACING_SYMBOLS_H
+#define OPENTRACING_SYMBOLS_H
+
+#include <opentracing/config.h>
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4251)
+#endif
+
+#ifdef _MSC_VER
+
+#define OPENTRACING_EXPORT __declspec(dllexport)
+
+// Export if this is our own source, otherwise import:
+#ifndef OPENTRACING_STATIC
+#ifdef OPENTRACING_EXPORTS
+#define OPENTRACING_API __declspec(dllexport)
+#else // OPENTRACING_STATIC
+#define OPENTRACING_API __declspec(dllimport)
+#endif // OPENTRACING_EXPORTS
+#endif // OPENTRACING_STATIC
+
+#endif // _MSC_VER
+
+#ifndef OPENTRACING_EXPORT
+#define OPENTRACING_EXPORT
+#endif
+
+#ifndef OPENTRACING_API
+#define OPENTRACING_API
+#endif
+
+#endif // OPENTRACING_SYMBOLS_H
diff --git a/include/opentracing/tracer.h b/include/opentracing/tracer.h
new file mode 100644
index 0000000..a4a125a
--- /dev/null
+++ b/include/opentracing/tracer.h
@@ -0,0 +1,277 @@
+#ifndef OPENTRACING_TRACER_H
+#define OPENTRACING_TRACER_H
+
+#include <opentracing/propagation.h>
+#include <opentracing/span.h>
+#include <opentracing/string_view.h>
+#include <opentracing/symbols.h>
+#include <opentracing/util.h>
+#include <opentracing/version.h>
+#include <chrono>
+#include <initializer_list>
+#include <iosfwd>
+#include <memory>
+#include <utility>
+#include <vector>
+
+namespace opentracing {
+BEGIN_OPENTRACING_ABI_NAMESPACE
+// StartSpanOptions allows Tracer.StartSpan() callers a mechanism to override
+// the start timestamp, specify Span References, and make a single Tag or
+// multiple Tags available at Span start time.
+//
+// StartSpan() callers should look at the StartSpanOption interface and
+// implementations available in this library.
+struct StartSpanOptions {
+ // start_system_timestamp and start_steady_timestamp override the Span's start
+ // time, or implicitly become std::chrono::system_clock::now() and
+ // std::chrono::steady_clock::now() if both are equal to the epoch (default
+ // behavior).
+ //
+ // If one of the timestamps is set but not the other, the set timestamp is
+ // used to estimate the corresponding timestamp of the other.
+ SystemTime start_system_timestamp;
+ SteadyTime start_steady_timestamp;
+
+ // Zero or more causal references to other Spans (via their SpanContext).
+ // If empty, start a "root" Span (i.e., start a new trace).
+ //
+ // Any nullptrs provided will be ignored.
+ std::vector<std::pair<SpanReferenceType, const SpanContext*>> references;
+
+ // Zero or more tags to apply to the newly created span.
+ std::vector<std::pair<std::string, Value>> tags;
+};
+
+// StartSpanOption instances (zero or more) may be passed to Tracer.StartSpan.
+class StartSpanOption {
+ public:
+ StartSpanOption(const StartSpanOption&) = delete;
+
+ virtual ~StartSpanOption() = default;
+
+ virtual void Apply(StartSpanOptions& options) const noexcept = 0;
+
+ protected:
+ StartSpanOption() = default;
+};
+
+// Tracer is a simple, thin interface for Span creation and SpanContext
+// propagation.
+class OPENTRACING_API Tracer {
+ public:
+ virtual ~Tracer() = default;
+
+ // Create, start, and return a new Span with the given `operationName` and
+ // incorporate the given StartSpanOption `option_list`.
+ //
+ // A Span with no SpanReference options (e.g., opentracing::ChildOf() or
+ // opentracing::FollowsFrom()) becomes the root of its own trace.
+ //
+ // Examples:
+ //
+ // opentracing::Tracer& tracer = ...
+ //
+ // // The root-span case:
+ // auto span = tracer.StartSpan("GetFeed")
+ //
+ // // The vanilla child span case:
+ // auto span = tracer.StartSpan(
+ // "GetFeed",
+ // {opentracing::ChildOf(&parentSpan.context())})
+ //
+ // // All the bells and whistles:
+ // auto span = tracer.StartSpan(
+ // "GetFeed",
+ // {opentracing::ChildOf(&parentSpan.context()),
+ // opentracing::Tag{"user_agent", loggedReq.UserAgent},
+ // opentracing::StartTimestamp(loggedReq.timestamp())})
+ //
+ // If StartSpan is called after Close, it leaves the Tracer in a valid
+ // state, but its behavior is unspecified.
+ std::unique_ptr<Span> StartSpan(
+ string_view operation_name,
+ std::initializer_list<option_wrapper<StartSpanOption>> option_list = {})
+ const noexcept {
+ StartSpanOptions options;
+ for (const auto& option : option_list) option.get().Apply(options);
+ return StartSpanWithOptions(operation_name, options);
+ }
+
+ virtual std::unique_ptr<Span> StartSpanWithOptions(
+ string_view operation_name, const StartSpanOptions& options) const
+ noexcept = 0;
+
+ // Inject() takes the `sc` SpanContext instance and injects it for propagation
+ // within `carrier`.
+ //
+ // OpenTracing defines a common set of `carrier` interfaces.
+ //
+ // Throws only if `writer` does.
+ //
+ // If `writer` is an `std::ostream`, then Inject() propagates `sc` as a blob
+ // of binary data.
+ virtual expected<void> Inject(const SpanContext& sc,
+ std::ostream& writer) const = 0;
+
+ virtual expected<void> Inject(const SpanContext& sc,
+ const TextMapWriter& writer) const = 0;
+
+ virtual expected<void> Inject(const SpanContext& sc,
+ const HTTPHeadersWriter& writer) const = 0;
+
+ virtual expected<void> Inject(const SpanContext& sc,
+ const CustomCarrierWriter& writer) const {
+ return writer.Inject(*this, sc);
+ }
+
+ // Extract() returns a SpanContext instance given `carrier`.
+ //
+ // OpenTracing defines a common set of `carrier` interfaces.
+ //
+ // Returns a `SpanContext` that is `non-null` on success or nullptr if no span
+ // is found; otherwise an std::error_code.
+ //
+ // Throws only if `reader` does.
+ virtual expected<std::unique_ptr<SpanContext>> Extract(
+ std::istream& reader) const = 0;
+
+ virtual expected<std::unique_ptr<SpanContext>> Extract(
+ const TextMapReader& reader) const = 0;
+
+ virtual expected<std::unique_ptr<SpanContext>> Extract(
+ const HTTPHeadersReader& reader) const = 0;
+
+ virtual expected<std::unique_ptr<SpanContext>> Extract(
+ const CustomCarrierReader& reader) const {
+ return reader.Extract(*this);
+ }
+
+ // Close is called when a tracer is finished processing spans. It is not
+ // required to be called and its effect is unspecified. For example, an
+ // implementation might use this function to flush buffered spans to its
+ // recording system and failing to call it could result in some spans being
+ // dropped.
+ virtual void Close() noexcept {}
+
+ // GlobalTracer returns the global tracer.
+ static std::shared_ptr<Tracer> Global() noexcept;
+
+ // InitGlobalTracer sets the global tracer pointer, returns the
+ // former global tracer value.
+ static std::shared_ptr<Tracer> InitGlobal(
+ std::shared_ptr<Tracer> tracer) noexcept;
+
+ static bool IsGlobalTracerRegistered() noexcept;
+};
+
+// StartTimestamp is a StartSpanOption that sets an explicit start timestamp for
+// the new Span.
+class StartTimestamp : public StartSpanOption {
+ public:
+ StartTimestamp(SystemTime system_when, SteadyTime steady_when) noexcept
+ : system_when_(system_when), steady_when_(steady_when) {}
+
+ StartTimestamp(SystemTime system_when) noexcept
+ : system_when_(system_when),
+ steady_when_(convert_time_point<SteadyClock>(system_when_)) {}
+
+ // Construct a timestamp using a duration from the epoch of std::time_t.
+ // From the documentation on std::time_t's epoch:
+ // Although not defined, this is almost always an integral value holding
+ // the number of seconds (not counting leap seconds) since 00:00, Jan 1
+ // 1970 UTC, corresponding to POSIX time
+ // See http://en.cppreference.com/w/cpp/chrono/c/time_t
+ template <class Rep, class Period>
+ explicit StartTimestamp(
+ const std::chrono::duration<Rep, Period>& time_since_epoch) noexcept
+ : StartTimestamp(SystemClock::from_time_t(std::time_t(0)) +
+ std::chrono::duration_cast<SystemClock::duration>(
+ time_since_epoch)) {}
+
+ StartTimestamp(const StartTimestamp& other) noexcept
+ : StartSpanOption(),
+ system_when_(other.system_when_),
+ steady_when_(other.steady_when_) {}
+
+ void Apply(StartSpanOptions& options) const noexcept override {
+ options.start_system_timestamp = system_when_;
+ options.start_steady_timestamp = steady_when_;
+ }
+
+ private:
+ SystemTime system_when_;
+ SteadyTime steady_when_;
+};
+
+// SpanReference is a StartSpanOption that pairs a SpanReferenceType and a
+// referenced SpanContext. See the SpanReferenceType documentation for
+// supported relationships.
+//
+// If the referenced SpanContext is a nullptr, it is ignored. The passed
+// SpanContext is copied during Span construction and the pointer is not
+// retained.
+class SpanReference : public StartSpanOption {
+ public:
+ SpanReference(SpanReferenceType type, const SpanContext* referenced) noexcept
+ : type_(type), referenced_(referenced) {}
+
+ SpanReference(const SpanReference& other) noexcept
+ : StartSpanOption(), type_(other.type_), referenced_(other.referenced_) {}
+
+ void Apply(StartSpanOptions& options) const noexcept override {
+ try {
+ if (referenced_) options.references.emplace_back(type_, referenced_);
+ } catch (const std::bad_alloc&) {
+ // Ignore reference if memory can't be allocated for it.
+ }
+ }
+
+ private:
+ SpanReferenceType type_;
+ const SpanContext* referenced_;
+};
+
+// ChildOf returns a StartSpanOption pointing to a dependent parent span.
+//
+// See ChildOfRef, SpanReference
+inline SpanReference ChildOf(const SpanContext* span_context) noexcept {
+ return {SpanReferenceType::ChildOfRef, span_context};
+}
+
+// FollowsFrom returns a StartSpanOption pointing to a parent Span that caused
+// the child Span but does not directly depend on its result in any way.
+//
+// See FollowsFromRef, SpanReference
+inline SpanReference FollowsFrom(const SpanContext* span_context) noexcept {
+ return {SpanReferenceType::FollowsFromRef, span_context};
+}
+
+// SetTag may be passed as a StartSpanOption to add a tag to new spans,
+// for example:
+//
+// tracer.StartSpan("opName", SetTag{"Key", value})
+class SetTag : public StartSpanOption {
+ public:
+ SetTag(string_view key, const Value& value) noexcept
+ : key_(key), value_(value) {}
+
+ SetTag(const SetTag& other) noexcept
+ : StartSpanOption(), key_(other.key_), value_(other.value_) {}
+
+ void Apply(StartSpanOptions& options) const noexcept override {
+ try {
+ options.tags.emplace_back(key_, value_);
+ } catch (const std::bad_alloc&) {
+ // Ignore tag if memory can't be allocated for it.
+ }
+ }
+
+ private:
+ const string_view key_;
+ const Value& value_;
+};
+END_OPENTRACING_ABI_NAMESPACE
+} // namespace opentracing
+
+#endif // OPENTRACING_TRACER_H
diff --git a/include/opentracing/tracer_factory.h b/include/opentracing/tracer_factory.h
new file mode 100644
index 0000000..622fa5b
--- /dev/null
+++ b/include/opentracing/tracer_factory.h
@@ -0,0 +1,56 @@
+#ifndef OPENTRACING_TRACER_FACTORY_H
+#define OPENTRACING_TRACER_FACTORY_H
+
+#include <opentracing/symbols.h>
+#include <opentracing/tracer.h>
+#include <opentracing/version.h>
+
+namespace opentracing {
+BEGIN_OPENTRACING_ABI_NAMESPACE
+// Returns the std::error_category class used for tracer factory errors.
+//
+// See
+// http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-1.html
+// https://ned14.github.io/boost.outcome/md_doc_md_03-tutorial_b.html
+OPENTRACING_API const std::error_category& tracer_factory_error_category();
+
+// `configuration_parse_error` occurs when the configuration string used to
+// construct a tracer does not adhere to the expected format.
+const std::error_code configuration_parse_error(
+ 1, tracer_factory_error_category());
+
+// `invalid_configuration_error` occurs if the requested configuration for a
+// tracer has invalid values.
+const std::error_code invalid_configuration_error(
+ 2, tracer_factory_error_category());
+
+// TracerFactory constructs tracers from configuration strings.
+class OPENTRACING_API TracerFactory {
+ public:
+ virtual ~TracerFactory() = default;
+
+ // Creates a tracer with the requested `configuration`.
+ //
+ // Example,
+ // const char* configuration = R"(
+ // "collector": "localhost:123",
+ // "max_buffered_spans": 500
+ // )";
+ // std:string error_message;
+ // auto tracer_maybe = tracer_factory->MakeTracer(configuration,
+ // error_message);
+ // if (tracer_mabye) {
+ // // success
+ // std::shared_ptr<opentracing::Tracer> tracer = *tracer_maybe;
+ // } else {
+ // // failure
+ // std::error_code error = tracer_maybe.error();
+ // // `error_message` may also contain a more descriptive message
+ // }
+ virtual expected<std::shared_ptr<Tracer>> MakeTracer(
+ const char* configuration, std::string& error_message) const noexcept = 0;
+};
+END_OPENTRACING_ABI_NAMESPACE
+} // namespace opentracing
+
+#endif // OPENTRACING_TRACER_FACTORY_H
diff --git a/include/opentracing/util.h b/include/opentracing/util.h
new file mode 100644
index 0000000..f3916cb
--- /dev/null
+++ b/include/opentracing/util.h
@@ -0,0 +1,84 @@
+#ifndef OPENTRACING_UTIL_H
+#define OPENTRACING_UTIL_H
+
+#include <opentracing/string_view.h>
+#include <opentracing/version.h>
+#include <chrono>
+#include <system_error>
+
+// expected uses a C++11 implementation that follows the std::expected standard
+// library proposal.
+//
+// See https://github.com/martinmoene/expected-lite
+// https://github.com/viboes/std-make/blob/master/doc/proposal/expected/d0323r2.md
+#include <opentracing/expected/expected.hpp>
+
+namespace opentracing {
+BEGIN_OPENTRACING_ABI_NAMESPACE
+using SystemClock = std::chrono::system_clock;
+using SteadyClock = std::chrono::steady_clock;
+using SystemTime = SystemClock::time_point;
+using SteadyTime = SteadyClock::time_point;
+
+// This is unsafe to do.
+//
+// This is like an unsafe std::reference_wrapper<> that allows taking
+// references to temporaries. It must only be used for temporary
+// SpanStartOption and SpanFinishOption objects.
+template <typename T>
+class option_wrapper {
+ public:
+ option_wrapper(const T &opt) : ptr_(&opt) {}
+
+ // This will dangle unless it is only used for short-lived initializer lists.
+ const T &get() const { return *ptr_; }
+
+ private:
+ const T *ptr_;
+};
+
+// Support conversion between time_points from different clocks. There's no
+// standard way to get the difference in epochs between clocks, so this uses
+// an approximation suggested by Howard Hinnant.
+//
+// See https://stackoverflow.com/a/35282833/4447365
+template <class ToClock, class FromClock, class Duration,
+ typename std::enable_if<
+ !std::is_same<FromClock, ToClock>::value>::type * = nullptr>
+typename ToClock::time_point convert_time_point(
+ std::chrono::time_point<FromClock, Duration> from_time_point) {
+ auto from_now = FromClock::now();
+ auto to_now = ToClock::now();
+ return to_now + std::chrono::duration_cast<typename ToClock::duration>(
+ from_time_point - from_now);
+}
+
+template <class ToClock, class FromClock, class Duration,
+ typename std::enable_if<std::is_same<FromClock, ToClock>::value>::type
+ * = nullptr>
+typename ToClock::time_point convert_time_point(
+ std::chrono::time_point<FromClock, Duration> from_time_point) {
+ return std::chrono::time_point_cast<typename ToClock::time_point::duration>(
+ from_time_point);
+}
+
+// std::error_code's have default comparison operators; however, they make use
+// of singleton addresses which can cause comparisons to fail when multiple
+// versions of the opentracing library are linked in. Since this is a common
+// deployment scenario when making OpenTracing plugins, we add this utility
+// function to make comparing std::error_code across libraries easier.
+//
+// Note: There's a proposed change to the C++ standard that addresses this
+// issue. See
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1196r0.html
+inline bool are_errors_equal(std::error_code lhs,
+ std::error_code rhs) noexcept {
+ return opentracing::string_view{lhs.category().name()} ==
+ opentracing::string_view{rhs.category().name()} &&
+ lhs.value() == rhs.value();
+}
+
+END_OPENTRACING_ABI_NAMESPACE
+} // namespace opentracing
+
+#endif // OPENTRACING_UTIL_H
diff --git a/include/opentracing/value.h b/include/opentracing/value.h
new file mode 100644
index 0000000..1c91f8b
--- /dev/null
+++ b/include/opentracing/value.h
@@ -0,0 +1,68 @@
+#ifndef OPENTRACING_VALUE_H
+#define OPENTRACING_VALUE_H
+
+#include <opentracing/string_view.h>
+#include <opentracing/version.h>
+#include <cstdint>
+#include <opentracing/variant/variant.hpp>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace opentracing {
+BEGIN_OPENTRACING_ABI_NAMESPACE
+// Variant value types for span tags and log payloads.
+class Value;
+
+typedef std::unordered_map<std::string, Value> Dictionary;
+typedef std::vector<Value> Values;
+typedef util::variant<bool, double, int64_t, uint64_t, std::string,
+ opentracing::string_view, std::nullptr_t, const char*,
+ util::recursive_wrapper<Values>,
+ util::recursive_wrapper<Dictionary>>
+ variant_type;
+
+class Value : public variant_type {
+ public:
+ Value() noexcept : variant_type(nullptr) {}
+ Value(std::nullptr_t) noexcept : variant_type(nullptr) {}
+
+ // variant_type's constructors will do some undesirable casting, for example
+ // variant_type(123)
+ // will construct a bool variant; hence, constructors are expanded
+ // out so as to provide more sensible behavior.
+ Value(bool x) noexcept : variant_type(x) {}
+
+ template <typename T,
+ typename std::enable_if<std::is_integral<T>::value &&
+ std::is_signed<T>::value>::type* = nullptr>
+ Value(T t) noexcept : variant_type(static_cast<int64_t>(t)) {}
+
+ template <typename T, typename std::enable_if<
+ std::is_integral<T>::value &&
+ std::is_unsigned<T>::value>::type* = nullptr>
+ Value(T t) noexcept : variant_type(static_cast<uint64_t>(t)) {}
+
+ template <typename T, typename std::enable_if<
+ std::is_floating_point<T>::value>::type* = nullptr>
+ Value(T t) noexcept : variant_type(static_cast<double>(t)) {}
+
+ Value(const char* s) noexcept : variant_type(s) {}
+
+ template <int N>
+ Value(const char (&cstr)[N]) : variant_type(std::string(cstr)) {}
+
+ Value(const std::string& s) : variant_type(s) {}
+ Value(std::string&& s) : variant_type(std::move(s)) {}
+ Value(opentracing::string_view s) noexcept : variant_type(s) {}
+
+ Value(const Values& values) : variant_type(values) {}
+ Value(Values&& values) : variant_type(std::move(values)) {}
+
+ Value(const Dictionary& values) : variant_type(values) {}
+ Value(Dictionary&& values) : variant_type(std::move(values)) {}
+};
+END_OPENTRACING_ABI_NAMESPACE
+} // namespace opentracing
+
+#endif // OPENTRACING_VALUE_H