.. _program_listing_file_include_opentelemetry_context_runtime_context.h: Program Listing for File runtime_context.h ========================================== |exhale_lsh| :ref:`Return to documentation for file ` (``include/opentelemetry/context/runtime_context.h``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 #pragma once #include "opentelemetry/context/context.h" OPENTELEMETRY_BEGIN_NAMESPACE namespace context { // The Token object provides is returned when attaching objects to the // RuntimeContext object and is associated with a context object, and // can be provided to the RuntimeContext Detach method to remove the // associated context from the RuntimeContext. class Token { public: bool operator==(const Context &other) const noexcept { return context_ == other; } ~Token(); private: friend class RuntimeContextStorage; Token() noexcept = default; // A constructor that sets the token's Context object to the // one that was passed in. Token(const Context &context) : context_(context) {} const Context context_; }; class RuntimeContextStorage { public: virtual Context GetCurrent() noexcept = 0; virtual nostd::unique_ptr Attach(const Context &context) noexcept = 0; virtual bool Detach(Token &token) noexcept = 0; virtual ~RuntimeContextStorage(){}; protected: nostd::unique_ptr CreateToken(const Context &context) noexcept { return nostd::unique_ptr(new Token(context)); } }; static RuntimeContextStorage *GetDefaultStorage() noexcept; // Provides a wrapper for propagating the context object globally. // // By default, a thread-local runtime context storage is used. class RuntimeContext { public: // Return the current context. static Context GetCurrent() noexcept { return GetRuntimeContextStorage()->GetCurrent(); } // Sets the current 'Context' object. Returns a token // that can be used to reset to the previous Context. static nostd::unique_ptr Attach(const Context &context) noexcept { return GetRuntimeContextStorage()->Attach(context); } // Resets the context to a previous value stored in the // passed in token. Returns true if successful, false otherwise static bool Detach(Token &token) noexcept { return GetRuntimeContextStorage()->Detach(token); } // Sets the Key and Value into the passed in context or if a context is not // passed in, the RuntimeContext. // Should be used to SetValues to the current RuntimeContext, is essentially // equivalent to RuntimeContext::GetCurrent().SetValue(key,value). Keep in // mind that the current RuntimeContext will not be changed, and the new // context will be returned. static Context SetValue(nostd::string_view key, const ContextValue &value, Context *context = nullptr) noexcept { Context temp_context; if (context == nullptr) { temp_context = GetCurrent(); } else { temp_context = *context; } return temp_context.SetValue(key, value); } // Returns the value associated with the passed in key and either the // passed in context* or the runtime context if a context is not passed in. // Should be used to get values from the current RuntimeContext, is // essentially equivalent to RuntimeContext::GetCurrent().GetValue(key). static ContextValue GetValue(nostd::string_view key, Context *context = nullptr) noexcept { Context temp_context; if (context == nullptr) { temp_context = GetCurrent(); } else { temp_context = *context; } return temp_context.GetValue(key); } static void SetRuntimeContextStorage(nostd::shared_ptr storage) noexcept { GetStorage() = storage; } private: static nostd::shared_ptr GetRuntimeContextStorage() noexcept { return GetStorage(); } static nostd::shared_ptr &GetStorage() noexcept { static nostd::shared_ptr context(GetDefaultStorage()); return context; } }; inline Token::~Token() { context::RuntimeContext::Detach(*this); } // The ThreadLocalContextStorage class is a derived class from // RuntimeContextStorage and provides a wrapper for propogating context through // cpp thread locally. This file must be included to use the RuntimeContext // class if another implementation has not been registered. class ThreadLocalContextStorage : public RuntimeContextStorage { public: ThreadLocalContextStorage() noexcept = default; // Return the current context. Context GetCurrent() noexcept override { return GetStack().Top(); } // Resets the context to the value previous to the passed in token. This will // also detach all child contexts of the passed in token. // Returns true if successful, false otherwise. bool Detach(Token &token) noexcept override { // In most cases, the context to be detached is on the top of the stack. if (token == GetStack().Top()) { GetStack().Pop(); return true; } if (!GetStack().Contains(token)) { return false; } while (!(token == GetStack().Top())) { GetStack().Pop(); } GetStack().Pop(); return true; } // Sets the current 'Context' object. Returns a token // that can be used to reset to the previous Context. nostd::unique_ptr Attach(const Context &context) noexcept override { GetStack().Push(context); return CreateToken(context); } private: // A nested class to store the attached contexts in a stack. class Stack { friend class ThreadLocalContextStorage; Stack() noexcept : size_(0), capacity_(0), base_(nullptr){}; // Pops the top Context off the stack and returns it. Context Pop() noexcept { if (size_ == 0) { return Context(); } size_ -= 1; return base_[size_]; } bool Contains(const Token &token) const noexcept { for (size_t pos = size_; pos > 0; --pos) { if (token == base_[pos - 1]) { return true; } } return false; } // Returns the Context at the top of the stack. Context Top() const noexcept { if (size_ == 0) { return Context(); } return base_[size_ - 1]; } // Pushes the passed in context pointer to the top of the stack // and resizes if necessary. void Push(const Context &context) noexcept { size_++; if (size_ > capacity_) { Resize(size_ * 2); } base_[size_ - 1] = context; } // Reallocates the storage array to the pass in new capacity size. void Resize(size_t new_capacity) noexcept { size_t old_size = size_ - 1; if (new_capacity == 0) { new_capacity = 2; } Context *temp = new Context[new_capacity]; if (base_ != nullptr) { // vs2015 does not like this construct considering it unsafe: // - std::copy(base_, base_ + old_size, temp); // Ref. // https://stackoverflow.com/questions/12270224/xutility2227-warning-c4996-std-copy-impl for (size_t i = 0; i < (std::min)(old_size, new_capacity); i++) { temp[i] = base_[i]; } delete[] base_; } base_ = temp; } ~Stack() noexcept { delete[] base_; } size_t size_; size_t capacity_; Context *base_; }; Stack &GetStack() { static thread_local Stack stack_ = Stack(); return stack_; } }; static RuntimeContextStorage *GetDefaultStorage() noexcept { return new ThreadLocalContextStorage(); } } // namespace context OPENTELEMETRY_END_NAMESPACE