wilson_span.h 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. #pragma once
  2. #include <library/cpp/actors/core/actor.h>
  3. #include <library/cpp/actors/core/actorsystem.h>
  4. #include <opentelemetry/proto/trace/v1/trace.pb.h>
  5. #include <util/generic/hash.h>
  6. #include <util/datetime/cputimer.h>
  7. #include "wilson_trace.h"
  8. namespace NWilson {
  9. enum class ERelation {
  10. FollowsFrom,
  11. ChildOf,
  12. };
  13. namespace NTraceProto = opentelemetry::proto::trace::v1;
  14. namespace NCommonProto = opentelemetry::proto::common::v1;
  15. struct TArrayValue;
  16. struct TKeyValueList;
  17. struct TBytes;
  18. using TAttributeValue = std::variant<
  19. TString,
  20. bool,
  21. i64,
  22. double,
  23. TArrayValue,
  24. TKeyValueList,
  25. TBytes
  26. >;
  27. struct TArrayValue : std::vector<TAttributeValue> {};
  28. struct TKeyValueList : THashMap<TString, TAttributeValue> {};
  29. struct TBytes : TString {};
  30. void SerializeKeyValue(TString key, TAttributeValue value, NCommonProto::KeyValue *pb);
  31. enum class EFlags : ui32 {
  32. NONE = 0,
  33. AUTO_END = 1,
  34. };
  35. Y_DECLARE_FLAGS(TFlags, EFlags);
  36. Y_DECLARE_OPERATORS_FOR_FLAGS(TFlags);
  37. class TSpan {
  38. struct TData {
  39. const TInstant StartTime;
  40. const ui64 StartCycles;
  41. const TTraceId TraceId;
  42. NTraceProto::Span Span;
  43. TFlags Flags;
  44. int UncaughtExceptions = std::uncaught_exceptions();
  45. bool Sent = false;
  46. bool Ignored = false;
  47. TData(TInstant startTime, ui64 startCycles, TTraceId traceId, TFlags flags)
  48. : StartTime(startTime)
  49. , StartCycles(startCycles)
  50. , TraceId(std::move(traceId))
  51. , Flags(flags)
  52. {}
  53. ~TData() {
  54. Y_VERIFY_DEBUG(Sent || Ignored);
  55. }
  56. };
  57. std::unique_ptr<TData> Data;
  58. public:
  59. TSpan() = default;
  60. TSpan(const TSpan&) = delete;
  61. TSpan(TSpan&&) = default;
  62. TSpan(ui8 verbosity, TTraceId parentId, std::optional<TString> name, TFlags flags = EFlags::NONE)
  63. : Data(parentId
  64. ? std::make_unique<TData>(TInstant::Now(), GetCycleCount(), parentId.Span(verbosity), flags)
  65. : nullptr)
  66. {
  67. if (Y_UNLIKELY(*this)) {
  68. if (verbosity <= parentId.GetVerbosity()) {
  69. if (!parentId.IsRoot()) {
  70. Data->Span.set_parent_span_id(parentId.GetSpanIdPtr(), parentId.GetSpanIdSize());
  71. }
  72. Data->Span.set_start_time_unix_nano(Data->StartTime.NanoSeconds());
  73. Data->Span.set_kind(opentelemetry::proto::trace::v1::Span::SPAN_KIND_INTERNAL);
  74. if (name) {
  75. Name(std::move(*name));
  76. }
  77. Attribute("node_id", NActors::TActivationContext::ActorSystem()->NodeId);
  78. } else {
  79. Data->Ignored = true; // ignore this span due to verbosity mismatch, still allowing child spans to be created
  80. }
  81. }
  82. }
  83. ~TSpan() {
  84. if (Y_UNLIKELY(*this)) {
  85. if (std::uncaught_exceptions() != Data->UncaughtExceptions) {
  86. EndError("span terminated due to stack unwinding");
  87. } else if (Data->Flags & EFlags::AUTO_END) {
  88. End();
  89. } else {
  90. EndError("unterminated span");
  91. }
  92. }
  93. }
  94. TSpan& operator =(const TSpan&) = delete;
  95. TSpan& operator =(TSpan&& other) {
  96. if (this != &other) {
  97. if (Y_UNLIKELY(*this)) {
  98. EndError("TSpan instance incorrectly overwritten");
  99. }
  100. Data = std::exchange(other.Data, nullptr);
  101. }
  102. return *this;
  103. }
  104. explicit operator bool() const {
  105. return Data && !Data->Sent && !Data->Ignored;
  106. }
  107. TSpan& EnableAutoEnd() {
  108. if (Y_UNLIKELY(*this)) {
  109. Data->Flags |= EFlags::AUTO_END;
  110. } else {
  111. VerifyNotSent();
  112. }
  113. return *this;
  114. }
  115. TSpan& Relation(ERelation /*relation*/) {
  116. if (Y_UNLIKELY(*this)) {
  117. // update relation in data somehow
  118. } else {
  119. VerifyNotSent();
  120. }
  121. return *this;
  122. }
  123. TSpan& Name(TString name) {
  124. if (Y_UNLIKELY(*this)) {
  125. Data->Span.set_name(std::move(name));
  126. } else {
  127. VerifyNotSent();
  128. }
  129. return *this;
  130. }
  131. TSpan& Attribute(TString name, TAttributeValue value) {
  132. if (Y_UNLIKELY(*this)) {
  133. SerializeKeyValue(std::move(name), std::move(value), Data->Span.add_attributes());
  134. } else {
  135. VerifyNotSent();
  136. }
  137. return *this;
  138. }
  139. TSpan& Event(TString name, TKeyValueList attributes) {
  140. if (Y_UNLIKELY(*this)) {
  141. auto *event = Data->Span.add_events();
  142. event->set_time_unix_nano(TimeUnixNano());
  143. event->set_name(std::move(name));
  144. for (auto&& [key, value] : attributes) {
  145. SerializeKeyValue(std::move(key), std::move(value), event->add_attributes());
  146. }
  147. } else {
  148. VerifyNotSent();
  149. }
  150. return *this;
  151. }
  152. TSpan& Link(const TTraceId& traceId, TKeyValueList attributes) {
  153. if (Y_UNLIKELY(*this)) {
  154. auto *link = Data->Span.add_links();
  155. link->set_trace_id(traceId.GetTraceIdPtr(), traceId.GetTraceIdSize());
  156. link->set_span_id(traceId.GetSpanIdPtr(), traceId.GetSpanIdSize());
  157. for (auto&& [key, value] : attributes) {
  158. SerializeKeyValue(std::move(key), std::move(value), link->add_attributes());
  159. }
  160. } else {
  161. VerifyNotSent();
  162. }
  163. return *this;
  164. }
  165. void EndOk() {
  166. if (Y_UNLIKELY(*this)) {
  167. auto *status = Data->Span.mutable_status();
  168. status->set_code(NTraceProto::Status::STATUS_CODE_OK);
  169. End();
  170. } else {
  171. VerifyNotSent();
  172. }
  173. }
  174. void EndError(TString error) {
  175. if (Y_UNLIKELY(*this)) {
  176. auto *status = Data->Span.mutable_status();
  177. status->set_code(NTraceProto::Status::STATUS_CODE_ERROR);
  178. status->set_message(std::move(error));
  179. End();
  180. } else {
  181. VerifyNotSent();
  182. }
  183. }
  184. void End() {
  185. if (Y_UNLIKELY(*this)) {
  186. Data->Span.set_trace_id(Data->TraceId.GetTraceIdPtr(), Data->TraceId.GetTraceIdSize());
  187. Data->Span.set_span_id(Data->TraceId.GetSpanIdPtr(), Data->TraceId.GetSpanIdSize());
  188. Data->Span.set_end_time_unix_nano(TimeUnixNano());
  189. Send();
  190. } else {
  191. VerifyNotSent();
  192. }
  193. }
  194. TTraceId GetTraceId() const {
  195. return Data ? TTraceId(Data->TraceId) : TTraceId();
  196. }
  197. private:
  198. void Send();
  199. ui64 TimeUnixNano() const {
  200. const TInstant now = Data->StartTime + CyclesToDuration(GetCycleCount() - Data->StartCycles);
  201. return now.NanoSeconds();
  202. }
  203. void VerifyNotSent() {
  204. Y_VERIFY_DEBUG(!Data || !Data->Sent, "span has been ended");
  205. }
  206. };
  207. } // NWilson