Skip to content

Commit

Permalink
Merge pull request #5 from satac2/context_api_content
Browse files Browse the repository at this point in the history
Context api content
  • Loading branch information
satac2 authored Jun 10, 2020
2 parents 8e02c07 + 7bceaab commit 4b9fc2b
Show file tree
Hide file tree
Showing 5 changed files with 324 additions and 36 deletions.
230 changes: 194 additions & 36 deletions api/include/opentelemetry/context/context.h
Original file line number Diff line number Diff line change
@@ -1,61 +1,219 @@
#pragma once


#include <map>
#include <string>
#include <mutex>

#include "opentelemetry/version.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace context
{

std::mutex context_id_mutex;

/*The context class provides a context identifier*/
class Context{

private:

/*The identifier itself*/
std::map<int, int> ctx_map_;

/*Used to track that last ContextKey identifier and create the next one */
static int last_key_identifier_;

/* Context: A constructor that accepts a key/value map*/
Context(std::map<int,int> ctx_map){
ctx_map_ = ctx_map;
}

public:

/*The ContextKey class is used to obscure access from the
* user to the context map. The identifier is used as a key
* to the context map.
*/
class ContextKey{
private:
friend class Context;

std::string key_name_;

int identifier_;


/* GetIdentifier: returns the identifier*/
int GetIdentifier(){
return identifier_;
}

/* ContextKey: constructs a new ContextKey with the
* passed in name and identifier.
*/
ContextKey(std::string key_name, int identifier){
key_name_ = key_name;
identifier_ = identifier;
}

public:

/* ContextKey: Consructs a new ContextKey with the passed in name
* and increments the identifier then assigns it to be the key's
* identifier.
*/
ContextKey(std::string key_name){
key_name_ = key_name;

context_id_mutex.lock();

Context::last_key_identifier_++;

identifier_ = Context::last_key_identifier_;

context_id_mutex.unlock();
}

};


/* Context: contructor, creates a context object with no key/value pairs
*/
Context(){
ctx_map_ = std::map<int,int> {};

}

/* Context: contructor, creates a context object from a map
* of keys and identifiers
*/
Context(ContextKey key, int value){
ctx_map_[key.GetIdentifier()] = value;
}


/* WriteValue: accepts a new key/value pair and then returns a new
* context that contains both the original pairs and the new pair.
*/
Context WriteValue(ContextKey key, int value){
std::map<int, int> temp_map = ctx_map_;

temp_map[key.GetIdentifier()] = value;

return Context(temp_map);
}


/* GetValue: Returns the value associated with the passed in key
*/
int GetValue(ContextKey key){
return ctx_map_[key.GetIdentifier()];
}

/* CreateKey: Returns a ContextKey that has the passed in name and the
* next available identifier.*/
ContextKey CreateKey(std::string key_name){
int id;

context_id_mutex.lock();

last_key_identifier_++;

id = last_key_identifier_;

context_id_mutex.unlock();

return ContextKey(key_name,id);
}


};



/* The token class provides an identifier that is used by
* the attach and detach methods to keep track of context
* objects.*/

class Token{
private:

Context ctx_;

public:

/* Token: A constructor that sets the token's Context object to the
* one that was passed in.
*/
Token(Context &ctx){
ctx_ = ctx;
}

/* GetContext: Returns the stored context object */
Context GetContext(){
return ctx_;
}

};


/* The RuntimeContext class provides a wrapper for
* propogating context through cpp*/
class RuntimeContext {
private:

static thread_local Context context_;

public:


/*The context class provides a context identifier*/
class Context{
private:
/*The identifier itself*/
std::map<std::string, int> ctx_;
RuntimeContext(){
context_ = Context();
}

public:
/* Context: contructor, creates a context object from a map
* of keys and identifiers
*/
Context(std::map<std::string, int> ctx);

};
/* RuntimeContext: A constructor that will set the context as
* the passed in context.
*/
RuntimeContext(Context &context){
context_ = context;
}

/* The token class provides an identifier that is used by
* the RuntimeContext attach and detach methods to keep track of context
* objects.*/
class Token{
Token();
};
/* attach: Sets the current 'Context' object. Returns a token
* that can be used to reset to the previous Context.
*/
Token Attach(Context &context){

Token old_context_token = Token(context_);

/* The RuntimeContext class provides a wrapper for
* propogating context through cpp*/
class RuntimeContext {
public:
context_ = context;

/* RuntimeContext: A constructor that will set the current
* context to the threading local.
*/
RuntimeContext();
return old_context_token;
}

/* attach: Sets the current 'Context' object. Returns a token
* that can be used to reset to the previous Context.
*/
static Token Attach(Context context);

/* GetCurrent: Return the current context.
*/
static Context GetCurrent(){
Context context = context_;
return context_;
}

/* get_current: Return the current context.
*/
static Context GetCurrent();


/* detach: Resets the context to a previous value.
*/
static void Detach(Token token);
/* Detach: Resets the context to a previous value stored in the
* passed in token.
*/
void Detach(Token &token){
context_ = token.GetContext();
}

};

thread_local Context RuntimeContext::context_ = Context();
int Context::last_key_identifier_ = 0;

};

}
OPENTELEMETRY_END_NAMESPACE
1 change: 1 addition & 0 deletions api/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
add_subdirectory(core)
add_subdirectory(context)
add_subdirectory(plugin)
add_subdirectory(nostd)
add_subdirectory(trace)
25 changes: 25 additions & 0 deletions api/test/context/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark")

cc_test(
name = "context_test",
srcs = [
"context_test.cc",
],
deps = [
"//api",
"@com_google_googletest//:gtest_main",
],
)

cc_test(
name = "runtimeContext_test",
srcs = [
"runtimeContext_test.cc",
],
copts = ["-Wall","-std=c++17"],
deps = [
"//api",
"@com_google_googletest//:gtest_main",
],
)

45 changes: 45 additions & 0 deletions api/test/context/context_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include "opentelemetry/context/context.h"

#include <gtest/gtest.h>

using namespace opentelemetry::context;

/* Tests whether the original context objects changes
* when you write to it.
*/
TEST(Context_test, is_context_immutable)
{

Context test_context = Context();

Context::ContextKey test_key = test_context.CreateKey("test_key");

EXPECT_EQ(test_context.GetValue(test_key), NULL);

Context new_test_context = test_context.WriteValue(test_key,7);

EXPECT_EQ(new_test_context.GetValue(test_key), 7);

EXPECT_EQ(test_context.GetValue(test_key), NULL);
}

/* Tests whether the new Context Objects inherits the keys and values
* of the original context object
*/
TEST(Context_test, context_write_new_object)
{


Context::ContextKey test_key = Context::ContextKey("test_key");

Context test_context = Context(test_key, 7);

Context::ContextKey foo_key = test_context.CreateKey("foo_key");

Context new_test_context = test_context.WriteValue(foo_key,1);

EXPECT_EQ(new_test_context.GetValue(test_key), 7);

EXPECT_EQ(new_test_context.GetValue(foo_key), 1);
}

59 changes: 59 additions & 0 deletions api/test/context/runtimeContext_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#include "opentelemetry/context/context.h"

#include <gtest/gtest.h>

using namespace opentelemetry::context;


/* Tests whether the runtimeContext object properly returns the current context
*/
TEST(runtimeContext_test, get_current_context)
{

Context::ContextKey test_key = Context::ContextKey("test_key");
Context test_context = Context(test_key, 7);

RuntimeContext test_runtime = RuntimeContext(test_context);

EXPECT_EQ(test_runtime.GetCurrent().GetValue(test_key),
test_context.GetValue(test_key));

}




/* Tests whether the runtimeContext object properly attaches and detaches
* the context object.
*/
TEST(runtimeContext_test, attach_detach_context)
{

Context::ContextKey test_key = Context::ContextKey("test_key");
Context test_context = Context(test_key, 7);

RuntimeContext test_runtime = RuntimeContext(test_context);

Context::ContextKey foo_key = Context::ContextKey("foo_key");
Context foo_context = Context(foo_key, 5);

EXPECT_EQ(test_runtime.GetCurrent().GetValue(test_key),
test_context.GetValue(test_key));
EXPECT_NE(test_runtime.GetCurrent().GetValue(foo_key),
foo_context.GetValue(foo_key));

Token test_token = test_runtime.Attach(foo_context);

EXPECT_NE(test_runtime.GetCurrent().GetValue(test_key),
test_context.GetValue(test_key));
EXPECT_EQ(test_runtime.GetCurrent().GetValue(foo_key),
foo_context.GetValue(foo_key));

test_runtime.Detach(test_token);

EXPECT_EQ(test_runtime.GetCurrent().GetValue(test_key),
test_context.GetValue(test_key));
EXPECT_NE(test_runtime.GetCurrent().GetValue(foo_key),
foo_context.GetValue(foo_key));
}

0 comments on commit 4b9fc2b

Please sign in to comment.