123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- // Copyright The OpenTelemetry Authors
- // SPDX-License-Identifier: Apache-2.0
- #pragma once
- #include <stddef.h>
- #include <algorithm>
- #include "opentelemetry/common/macros.h"
- #include "opentelemetry/context/context.h"
- #include "opentelemetry/context/context_value.h"
- #include "opentelemetry/nostd/shared_ptr.h"
- #include "opentelemetry/nostd/string_view.h"
- #include "opentelemetry/nostd/unique_ptr.h"
- #include "opentelemetry/version.h"
- OPENTELEMETRY_BEGIN_NAMESPACE
- namespace 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() noexcept;
- private:
- friend class RuntimeContextStorage;
- // 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_;
- };
- /**
- * RuntimeContextStorage is used by RuntimeContext to store Context frames.
- *
- * Custom context management strategies can be implemented by deriving from
- * this class and passing an initialized RuntimeContextStorage object to
- * RuntimeContext::SetRuntimeContextStorage.
- */
- class OPENTELEMETRY_EXPORT RuntimeContextStorage
- {
- public:
- /**
- * Return the current context.
- * @return the current context
- */
- virtual Context GetCurrent() noexcept = 0;
- /**
- * Set the current context.
- * @param the new current context
- * @return a token for the new current context. This never returns a nullptr.
- */
- virtual nostd::unique_ptr<Token> Attach(const Context &context) noexcept = 0;
- /**
- * Detach the context related to the given token.
- * @param token a token related to a context
- * @return true if the context could be detached
- */
- virtual bool Detach(Token &token) noexcept = 0;
- virtual ~RuntimeContextStorage() {}
- protected:
- nostd::unique_ptr<Token> CreateToken(const Context &context) noexcept
- {
- return nostd::unique_ptr<Token>(new Token(context));
- }
- };
- /**
- * Construct and return the default RuntimeContextStorage
- * @return a ThreadLocalContextStorage
- */
- static RuntimeContextStorage *GetDefaultStorage() noexcept;
- // Provides a wrapper for propagating the context object globally.
- //
- // By default, a thread-local runtime context storage is used.
- class OPENTELEMETRY_EXPORT 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<Token> 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);
- }
- /**
- * Provide a custom runtime context storage.
- *
- * This provides a possibility to override the default thread-local runtime
- * context storage. This has to be set before any spans are created by the
- * application, otherwise the behavior is undefined.
- *
- * @param storage a custom runtime context storage
- */
- static void SetRuntimeContextStorage(
- const nostd::shared_ptr<RuntimeContextStorage> &storage) noexcept
- {
- GetStorage() = storage;
- }
- /**
- * Provide a pointer to const runtime context storage.
- *
- * The returned pointer can only be used for extending the lifetime of the runtime context
- * storage.
- *
- */
- static nostd::shared_ptr<const RuntimeContextStorage> GetConstRuntimeContextStorage() noexcept
- {
- return GetRuntimeContextStorage();
- }
- private:
- static nostd::shared_ptr<RuntimeContextStorage> GetRuntimeContextStorage() noexcept
- {
- return GetStorage();
- }
- OPENTELEMETRY_API_SINGLETON static nostd::shared_ptr<RuntimeContextStorage> &GetStorage() noexcept
- {
- static nostd::shared_ptr<RuntimeContextStorage> context(GetDefaultStorage());
- return context;
- }
- };
- inline Token::~Token() noexcept
- {
- context::RuntimeContext::Detach(*this);
- }
- // The ThreadLocalContextStorage class is a derived class from
- // RuntimeContextStorage and provides a wrapper for propagating 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<Token> 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.
- void Pop() noexcept
- {
- if (size_ == 0)
- {
- return;
- }
- // Store empty Context before decrementing `size`, to ensure
- // the shared_ptr object (if stored in prev context object ) are released.
- // The stack is not resized, and the unused memory would be reutilised
- // for subsequent context storage.
- base_[size_ - 1] = Context();
- size_ -= 1;
- }
- 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;
- capacity_ = new_capacity;
- }
- ~Stack() noexcept { delete[] base_; }
- size_t size_;
- size_t capacity_;
- Context *base_;
- };
- OPENTELEMETRY_API_SINGLETON Stack &GetStack()
- {
- static thread_local Stack stack_ = Stack();
- return stack_;
- }
- };
- static RuntimeContextStorage *GetDefaultStorage() noexcept
- {
- return new ThreadLocalContextStorage();
- }
- } // namespace context
- OPENTELEMETRY_END_NAMESPACE
|