Skip to content

Commit

Permalink
Merge pull request open-telemetry#3 from Tianlin-Zhao/origin/propagators
Browse files Browse the repository at this point in the history
Origin/propagators
  • Loading branch information
Tianlin-Zhao authored Jul 27, 2020
2 parents 8faa168 + 61ef022 commit a99f620
Show file tree
Hide file tree
Showing 19 changed files with 1,386 additions and 790 deletions.
166 changes: 166 additions & 0 deletions api/include/opentelemetry/context/context.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
#pragma once

#include "opentelemetry/context/context_value.h"
#include "opentelemetry/nostd/shared_ptr.h"
#include "opentelemetry/nostd/string_view.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace context
{

// The context class provides a context identifier. Is built as a linked list
// of DataList nodes and each context holds a shared_ptr to a place within
// the list that determines which keys and values it has access to. All that
// come before and none that come after.
class Context
{

public:
// Creates a context object from a map of keys and identifiers, this will
// hold a shared_ptr to the head of the DataList linked list
template <class T>
Context(const T &keys_and_values)
{
head_ = nostd::shared_ptr<DataList>{new DataList(keys_and_values)};
}

// Creates a context object from a key and value, this will
// hold a shared_ptr to the head of the DataList linked list
Context(nostd::string_view key, ContextValue value)
{
head_ = nostd::shared_ptr<DataList>{new DataList(key, value)};
}

// Accepts a new iterable and then returns a new context that
// contains the new key and value data. It attaches the
// exisiting list to the end of the new list.
template <class T>
Context SetValues(T &values) noexcept
{
Context context = Context(values);
nostd::shared_ptr<DataList> &last = context.head_;
while (last->next_ != nullptr)
{
last = last->next_;
}
last->next_ = head_;
return context;
}

// Accepts a new iterable and then returns a new context that
// contains the new key and value data. It attaches the
// exisiting list to the end of the new list.
Context SetValue(nostd::string_view key, ContextValue value) noexcept
{
Context context = Context(key, value);
context.head_->next_ = head_;
return context;
}

// Returns the value associated with the passed in key.
context::ContextValue GetValue(const nostd::string_view key) noexcept
{
for (DataList *data = head_.get(); data != nullptr; data = data->next_.get())
{
if (key.size() == data->key_length_)
{
if (memcmp(key.data(), data->key_, data->key_length_) == 0)
{
return data->value_;
}
}
}
return (int64_t)0;
}

// Checks for key and returns true if found
bool HasKey(const nostd::string_view key) noexcept
{
for (DataList *data = head_.get(); data != nullptr; data = data->next_.get())
{
if (key.size() == data->key_length_)
{
if (memcmp(key.data(), data->key_, data->key_length_) == 0)
{
return true;
}
}
}
return false;
}

private:
Context() = default;

// A linked list to contain the keys and values of this context node
class DataList
{
public:
nostd::shared_ptr<DataList> next_;

char *key_;

size_t key_length_;

ContextValue value_;

DataList() { next_ = nullptr; }

// Builds a data list off of a key and value iterable and returns the head
template <class T>
DataList(const T &keys_and_vals) : key_{nullptr}
{
bool first = true;
auto *node = this;
for (auto &iter : keys_and_vals)
{
if (first)
{
*node = DataList(iter.first, iter.second);
first = false;
}
else
{
node->next_ = nostd::shared_ptr<DataList>(new DataList(iter.first, iter.second));
node = node->next_.get();
}
}
}

// Builds a data list with just a key and value, so it will just be the head
// and returns that head.
DataList(nostd::string_view key, ContextValue value)
{
key_ = new char[key.size()];
key_length_ = key.size();
memcpy(key_, key.data(), key.size() * sizeof(char));
value_ = value;
next_ = nostd::shared_ptr<DataList>{nullptr};
}

DataList &operator=(DataList &&other)
{
key_length_ = other.key_length_;
value_ = std::move(other.value_);
next_ = std::move(other.next_);

key_ = other.key_;
other.key_ = nullptr;

return *this;
}

~DataList()
{
if (key_ != nullptr)
{
delete[] key_;
}
}
};

// Head of the list which holds the keys and values of this context
nostd::shared_ptr<DataList> head_;
};
} // namespace context
OPENTELEMETRY_END_NAMESPACE
18 changes: 18 additions & 0 deletions api/include/opentelemetry/context/context_value.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once

#include <cstdint>

#include "opentelemetry/nostd/shared_ptr.h"
#include "opentelemetry/nostd/span.h"
#include "opentelemetry/nostd/unique_ptr.h"
#include "opentelemetry/nostd/variant.h"
#include "opentelemetry/trace/span_context.h"
#include "opentelemetry/version.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace context
{
using ContextValue =
nostd::variant<bool, int64_t, uint64_t, double, nostd::shared_ptr<trace::SpanContext>>;
} // namespace context
OPENTELEMETRY_END_NAMESPACE
66 changes: 58 additions & 8 deletions api/include/opentelemetry/nostd/string_view.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <algorithm>
#include <cstddef>
#include <cstring>
#include <ostream>
#include <stdexcept>
Expand All @@ -11,6 +12,9 @@
OPENTELEMETRY_BEGIN_NAMESPACE
namespace nostd
{

using Traits = std::char_traits<char>;

/**
* Back port of std::string_view to work with pre-cpp-17 compilers.
*
Expand All @@ -20,7 +24,9 @@ namespace nostd
class string_view
{
public:
static constexpr std::size_t npos = static_cast<std::size_t>(-1);
typedef std::size_t size_type;

static constexpr size_type npos = static_cast<size_type>(-1);

string_view() noexcept : length_(0), data_(nullptr) {}

Expand All @@ -30,25 +36,25 @@ class string_view
: length_(str.length()), data_(str.c_str())
{}

string_view(const char *str, size_t len) noexcept : length_(len), data_(str) {}
string_view(const char *str, size_type len) noexcept : length_(len), data_(str) {}

explicit operator std::string() const { return {data_, length_}; }

const char *data() const noexcept { return data_; }

bool empty() const noexcept { return length_ == 0; }

size_t length() const noexcept { return length_; }
size_type length() const noexcept { return length_; }

size_t size() const noexcept { return length_; }
size_type size() const noexcept { return length_; }

const char *begin() const noexcept { return data(); }

const char *end() const noexcept { return data() + length(); }

const char &operator[](std::size_t i) { return *(data() + i); }
const char &operator[](size_type i) { return *(data() + i); }

string_view substr(std::size_t pos, std::size_t n = npos) const
string_view substr(size_type pos, size_type n = npos) const
{
if (pos > length_)
{
Expand All @@ -62,11 +68,55 @@ class string_view
return string_view(data_ + pos, n);
}

int compare(string_view v) const noexcept
{
size_type len = std::min(size(), v.size());
int result = Traits::compare(data(), v.data(), len);
if (result == 0)
result = size() == v.size() ? 0 : (size() < v.size() ? -1 : 1);
return result;
};

int compare(size_type pos1, size_type count1, string_view v) const
{
return substr(pos1, count1).compare(v);
};

int compare(size_type pos1, size_type count1, string_view v, size_type pos2, size_type count2) const
{
return substr(pos1, count1).compare(v.substr(pos2, count2));
};

int compare(const char *s) const
{
return compare(string_view(s));
};

int compare(size_type pos1, size_type count1, const char *s) const
{
return substr(pos1, count1).compare(string_view(s));
};

int compare(size_type pos1, size_type count1, const char *s, size_type count2) const
{
return substr(pos1, count1).compare(string_view(s, count2));
};

bool operator<(const string_view v) const noexcept
{
return compare(v) < 0;
}

bool operator>(const string_view v) const noexcept
{
return compare(v) > 0;
}

private:
// Note: uses the same binary layout as libstdc++'s std::string_view
// See
// https://github.com/gcc-mirror/gcc/blob/e0c554e4da7310df83bb1dcc7b8e6c4c9c5a2a4f/libstdc%2B%2B-v3/include/std/string_view#L466-L467
size_t length_;
size_type length_;
const char *data_;
};

Expand Down Expand Up @@ -126,4 +176,4 @@ inline std::ostream &operator<<(std::ostream &os, string_view s)
return os.write(s.data(), static_cast<std::streamsize>(s.length()));
}
} // namespace nostd
OPENTELEMETRY_END_NAMESPACE
OPENTELEMETRY_END_NAMESPACE
59 changes: 59 additions & 0 deletions api/include/opentelemetry/propagators/composite_http_propagator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright 2020, OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include "opentelemetry/context/context.h"
#include "opentelemetry/trace/propagation/httptextformat.h"
#include "opentelemetry/nostd/span.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace propagators
{
// CompositeHTTPPropagator provides a mechanism for combining multiple
// propagators into a single one.
template <typename T>
class CompositeHTTPPropagator(trace::propagation::HTTPTextFormat<T>) {
public:
// Initializes a Composite Http Propagator with given propagators
CompositeHTTPPropagator(nostd::span<trace::propagation::HTTPTextFormat> &propagators) {
this.propagators_ = propagators;
}

// Run each of the configured propagators with the given context and carrier.
// Propagators are run in the order they are configured, if multiple
// propagators write the same context key, the propagator later in the list
// will override previous propagators.
// See opentelemetry.trace.propagation.httptextformat.HTTPTextFormat.extract
Extract(Getter get_from_carrier, const T &carrier, Context &context) {
for (nostd::span<trace::propagation::HTTPTextFormat>::iterator it = propagators_.begin(); it != propagators_.end(); it++) {
context = it->Extract(get_from_carrier, carrier, context);
}
return context;
}

// Run each of the configured propagators with the given context and carrier.
// Propagators are run in the order they are configured, if multiple
// propagators write the same carrier key, the propagator later in the list
// will override previous propagators.
// See `opentelemetry.trace.propagation.httptextformat.HTTPTextFormat.inject`
Inject(Setter set_from_carrier, T &carrier, const Context &context) {
for (nostd::span<trace::propagation::HTTPTextFormat>::iterator it = propagators_.begin(); it != propagators_.end(); it++) {
it->Inject(get_from_carrier, carrier, context);
}
}
private:
nostd::span<trace::propagation::HTTPTextFormat> propagators_;
}
}
Loading

0 comments on commit a99f620

Please sign in to comment.