#ifndef UBSE_MANAGER_TRACE_CONTEXT_H
#define UBSE_MANAGER_TRACE_CONTEXT_H
#include <atomic>
#include <chrono>
#include <mutex>
#include <random>
#include <string>
#include <thread>
#include "securec.h"
#ifdef __cplusplus
extern "C" {
#endif
extern thread_local char tls_traceId[37];
#ifdef __cplusplus
}
#endif
constexpr size_t TRACE_ID_SIZE = 37;
using uuid_t = unsigned char[16];
using UuidGenerateRandom = void (*)(uuid_t);
using UuidUnparse = void (*)(const uuid_t uu, char* out);
class TraceContext {
public:
static inline std::string GetTraceId()
{
if (!ensureInitialized()) {
return "";
}
if (tls_traceId[0] == '\0') {
generateTraceId();
}
return std::string(tls_traceId);
}
static inline char* GetTraceIdPtr()
{
if (!ensureInitialized()) {
return tls_traceId;
}
if (tls_traceId[0] == '\0') {
generateTraceId();
}
return tls_traceId;
}
static inline void SetTraceId(const std::string& traceId)
{
if (!ensureInitialized()) {
return;
}
if (traceId.empty()) {
return;
}
size_t copyLen = std::min(traceId.size(), TRACE_ID_SIZE - 1);
auto ret = memcpy_s(tls_traceId, TRACE_ID_SIZE, traceId.c_str(), copyLen);
if (ret == EOK) {
tls_traceId[copyLen] = '\0';
} else {
tls_traceId[0] = '\0';
}
}
static inline void Clear()
{
tls_traceId[0] = '\0';
}
static uint32_t InitUuid();
private:
static inline bool ensureInitialized()
{
static std::once_flag initFlag;
std::call_once(initFlag, []() { InitUuid(); });
return IsEnabled_.load(std::memory_order_acquire);
}
static inline void generateTraceId()
{
auto generateFunc = uuidGenerateRandomFunc_.load(std::memory_order_relaxed);
auto unparseFunc = uuidUnparseFunc_.load(std::memory_order_relaxed);
if (generateFunc && unparseFunc) {
uuid_t uuid;
generateFunc(uuid);
unparseFunc(uuid, tls_traceId);
tls_traceId[TRACE_ID_SIZE - 1] = '\0';
return;
}
fallbackGenerateTraceId();
}
static inline void fallbackGenerateTraceId()
{
thread_local std::mt19937_64 rng(std::random_device{}() ^
std::hash<std::thread::id>{}(std::this_thread::get_id()));
thread_local std::uniform_int_distribution<uint64_t> dist;
auto now = std::chrono::steady_clock::now().time_since_epoch().count();
auto tid = std::hash<std::thread::id>{}(std::this_thread::get_id());
auto random = dist(rng);
uint64_t high = static_cast<uint64_t>(now) ^ tid;
uint64_t low = random;
const size_t destSize = sizeof(tls_traceId);
errno_t ret = snprintf_s(tls_traceId,
destSize,
destSize - 1,
"%016lx-%016lx", static_cast<unsigned long>(high), static_cast<unsigned long>(low));
if (ret < 0) {
tls_traceId[0] = '\0';
} else {
tls_traceId[destSize - 1] = '\0';
}
}
static std::atomic<void*> uuidLib_;
static std::atomic<UuidGenerateRandom> uuidGenerateRandomFunc_;
static std::atomic<UuidUnparse> uuidUnparseFunc_;
static std::atomic<bool> IsEnabled_;
};
#endif