aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/actors/wilson/wilson_trace.h
blob: 1e2f03a1b874e8dabbdb8267031669f43603ba33 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#pragma once

#include <library/cpp/string_utils/base64/base64.h>

#include <util/stream/output.h>
#include <util/random/random.h>

#include <util/string/printf.h>

namespace NWilson {
    class TTraceId {
        ui64 TraceId; // Random id of topmost client request
        ui64 SpanId;  // Span id of part of request currently being executed

    private:
        TTraceId(ui64 traceId, ui64 spanId)
            : TraceId(traceId)
            , SpanId(spanId)
        {
        }

        static ui64 GenerateTraceId() {
            ui64 traceId = 0;
            while (!traceId) {
                traceId = RandomNumber<ui64>();
            }
            return traceId;
        }

        static ui64 GenerateSpanId() {
            return RandomNumber<ui64>();
        }

    public:
        using TSerializedTraceId = char[2 * sizeof(ui64)];

    public:
        TTraceId()
            : TraceId(0)
            , SpanId(0)
        {
        }

        explicit TTraceId(ui64 traceId)
            : TraceId(traceId)
            , SpanId(0)
        {
        }

        TTraceId(const TSerializedTraceId& in)
            : TraceId(reinterpret_cast<const ui64*>(in)[0])
            , SpanId(reinterpret_cast<const ui64*>(in)[1])
        {
        }

        // allow move semantic
        TTraceId(TTraceId&& other)
            : TraceId(other.TraceId)
            , SpanId(other.SpanId)
        {
            other.TraceId = 0;
            other.SpanId = 1; // explicitly mark invalid
        }

        TTraceId& operator=(TTraceId&& other) {
            TraceId = other.TraceId;
            SpanId = other.SpanId;
            other.TraceId = 0;
            other.SpanId = 1; // explicitly mark invalid
            return *this;
        }

        // do not allow implicit copy of trace id
        TTraceId(const TTraceId& other) = delete;
        TTraceId& operator=(const TTraceId& other) = delete;

        static TTraceId NewTraceId() {
            return TTraceId(GenerateTraceId(), 0);
        }

        // create separate branch from this point
        TTraceId SeparateBranch() const {
            return Clone();
        }

        TTraceId Clone() const {
            return TTraceId(TraceId, SpanId);
        }

        TTraceId Span() const {
            return *this ? TTraceId(TraceId, GenerateSpanId()) : TTraceId();
        }

        ui64 GetTraceId() const {
            return TraceId;
        }

        // Check if request tracing is enabled
        operator bool() const {
            return TraceId != 0;
        }

        // Output trace id into a string stream
        void Output(IOutputStream& s, const TTraceId& parentTraceId) const {
            union {
                ui8 buffer[3 * sizeof(ui64)];
                struct {
                    ui64 traceId;
                    ui64 spanId;
                    ui64 parentSpanId;
                } x;
            };

            x.traceId = TraceId;
            x.spanId = SpanId;
            x.parentSpanId = parentTraceId.SpanId;

            const size_t base64size = Base64EncodeBufSize(sizeof(x));
            char base64[base64size];
            char* end = Base64Encode(base64, buffer, sizeof(x));
            s << TStringBuf(base64, end);
        }

        // output just span id into stream
        void OutputSpanId(IOutputStream& s) const {
            const size_t base64size = Base64EncodeBufSize(sizeof(SpanId));
            char base64[base64size];
            char* end = Base64Encode(base64, reinterpret_cast<const ui8*>(&SpanId), sizeof(SpanId));

            // cut trailing padding character
            Y_VERIFY(end > base64 && end[-1] == '=');
            --end;

            s << TStringBuf(base64, end);
        }

        void CheckConsistency() {
            // if TraceId is zero, then SpanId must be zero too
            Y_VERIFY_DEBUG(*this || !SpanId);
        }

        friend bool operator==(const TTraceId& x, const TTraceId& y) {
            return x.TraceId == y.TraceId && x.SpanId == y.SpanId;
        }

        TString ToString() const {
            return Sprintf("%" PRIu64 ":%" PRIu64, TraceId, SpanId);
        }

        bool IsFromSameTree(const TTraceId& other) const {
            return TraceId == other.TraceId;
        }

        void Serialize(TSerializedTraceId* out) {
            ui64* p = reinterpret_cast<ui64*>(*out);
            p[0] = TraceId;
            p[1] = SpanId;
        }
    };

}