Skip to content

Commit

Permalink
feat(core): implement tracing
Browse files Browse the repository at this point in the history
  • Loading branch information
roby2014 committed Aug 21, 2024
1 parent e2a596e commit d8eba43
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 0 deletions.
1 change: 1 addition & 0 deletions core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ set(CUBOS_CORE_SOURCE

"src/tel/logging.cpp"
"src/tel/metrics.cpp"
"src/tel/tracing.cpp"

"src/thread/pool.cpp"
"src/thread/task.cpp"
Expand Down
82 changes: 82 additions & 0 deletions core/include/cubos/core/tel/tracing.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/// @file
/// @brief Tracing macros.
/// @ingroup core-tel

#pragma once

#include <chrono>
#include <string>
#include <thread>

namespace cubos::core::tel
{
class SpanManager
{
public:
class Span
{
public:
Span(const std::string& name, std::size_t level, const std::string& file, std::size_t line);
~Span();
std::string name();

private:
std::thread::id mId; ///< Thread id where span was invoked.
std::string mName; ///< The name of the scope.
std::string mFile; ///< The file from where it was invoked.
std::size_t mLine; ///< The line from where it was invoked.
std::chrono::time_point<std::chrono::high_resolution_clock> mStart; ///< Start time when constructed.
std::size_t mLevel; ///< Debug level
};

/// @brief Gets the current active span.
/// @return Span* Pointer to the current active span.
static Span* current();

/// @brief Decides next span name.
/// @example If current span is `foo` and a `bar` was invoked, this returns "foo:bar`.
/// @return Returns span name.
static std::string nextName(std::string name);

/// @brief Gets the count of active spans.
/// @return Span count.
static std::size_t count();

/// @brief Enters a new span.
/// @param s Pointer to the span to be entered.
static void enter(Span* s);

/// @brief Exits the current active span.
static void exit();

private:
SpanManager() = default;
};
} // namespace cubos::core::tel

#define SPAN(a, b) SPAN_INNER(a, b)
#define SPAN_INNER(a, b) a##b

/// @brief Constructs a new info span.
/// @param name Span name.
#define CUBOS_SPAN_INFO(name) \
SpanManager::Span SPAN(info_span_, __COUNTER__) \
{ \
name, 1, __FILE__, __LINE__ \
}

/// @brief Constructs a new trace span.
/// @param name Span name.
#define CUBOS_SPAN_TRACE(name) \
SpanManager::Span SPAN(trace_span_, __COUNTER__) \
{ \
name, 2, __FILE__, __LINE__ \
}

/// @brief Constructs a new debug span.
/// @param name Span name.
#define CUBOS_SPAN_DEBUG(name) \
SpanManager::Span SPAN(trace_span_, __COUNTER__) \
{ \
name, 3, __FILE__, __LINE__ \
}
81 changes: 81 additions & 0 deletions core/src/tel/tracing.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include <stack>

#include <cubos/core/tel/tracing.hpp>

using cubos::core::tel::SpanManager;

namespace
{
/// @brief Private type which stores the state of the span tracer.
struct State
{
std::stack<SpanManager::Span*> spans;
};
} // namespace

/// @brief Span tracer state singleton. Guarantees it is initialized exactly once, per thread, when needed.
/// @return Tracer state.
static State& state()
{
static thread_local State state{};
return state;
}

SpanManager::Span::Span(const std::string& name, std::size_t level, const std::string& file, std::size_t line)
: mId(std::this_thread::get_id())
, mName(SpanManager::nextName(name))
, mFile(file)
, mLine(line)
, mStart(std::chrono::time_point<std::chrono::high_resolution_clock>::clock::now())
, mLevel(level)
{
SpanManager::enter(this);
printf("START %s \n", mName.c_str());
}

SpanManager::Span::~Span()
{
auto now = std::chrono::time_point<std::chrono::high_resolution_clock>::clock::now();
std::chrono::duration<double, std::milli> elapsed = now - mStart;
// TODO store metric
printf("%f END %s - %lu - %lu - %s \n", elapsed.count(), mName.c_str(), mLevel, mLine, mFile.c_str());
SpanManager::exit();
}

std::string SpanManager::Span::name()
{
return mName;
}

SpanManager::Span* SpanManager::current()
{
return state().spans.empty() ? nullptr : state().spans.top();
}

std::string SpanManager::nextName(std::string name)
{
if (current() != nullptr)
{
name = current()->name() + ":" + name;
}

return name;
}

std::size_t SpanManager::count()
{
return state().spans.size();
}

void SpanManager::enter(Span* s)
{
state().spans.push(s);
}

void SpanManager::exit()
{
if (!state().spans.empty())
{
state().spans.pop();
}
}

0 comments on commit d8eba43

Please sign in to comment.